Haoi2018 strange backpack problem solution

Problem Portal: https://www.lydsy.com/JudgeOnline/problem.php?id=5302

For an item, let its volume be v, then, in the case of knapsack parameter p, it can reach the weight of multiples of gcd(v, p)

For two items, let their volumes be v1 and v2, then, in the case of knapsack parameter p, he can reach the weight of multiples of gcd(v1, v2, p)

For each item, we write down its gcd(v,p), the problem becomes given a x, how many sets of v are there, the gcd of all elements in the set can be divisible by x

We set dp[i][j] to represent how many combinations of the first i divisors of p are the combined gcd of j.

Next, we consider how to transfer

First give the pseudo code (without modulo):

for (i = 1; i <= divisor number; ++ i)

  for(j=1;j<=number of divisors;++j){

    x=gcd(ith divisor, jth divisor)dp[i][x]+=dp[i-1][j]*(2^divisor i number-1);

    dp[i][j]+=dp[i][j-1];

  }

This transfer method is a bit strange, and it is a good idea. Our usual dp is enumerated state, and then we are looking for a state that can be transferred to our enumerated state. This dp is to enumerate the states that have been calculated first. When calculating where these states can be transferred and updated, it is somewhat similar to the topological sorting dp writing method of noip2017 to improve the group day1T3.

On the AC code (wxy array is dp array, I haven't talked about some details, you can implement it yourself, ps: my constant is a bit large (two maps)):

#include <bits/stdc++.h>
using namespace std;
const int N=2e3+10;
const int md=1e9+7;
#define _l long long
int n,q,p,ys[N];
map<int,int>reff;
map<int,int>cnt;
_l p2[N*N],wxy[N][N],an[N];
int gcd(int x,int y){return x%y==0 ? y:gcd(y,x%y);}
int main(){
    scanf("%d%d%d",&n,&q,&p);
    int i;
    for(i=1;i*i<=p;++i)if(p%i==0){
        ys[++ys[0]]=i,reff[i]=ys[0];if(i*i!=p)ys[++ys[0]]=p/i,reff[p/i]=ys[0];
    }
    for(i=1;i<=n;++i){
        int x;scanf("%d",&x);x=gcd(max(x,p),min(x,p));
        ++cnt[x];
    }
    int j;p2[0]=1;
    for(i=1;i<=n;++i)p2[i]=(p2[i-1]*2)%md;wxy[0][reff[p]]=1;
    for(i=1;i<=ys[0];++i)for(j=1;j<=ys[0];++j){
        int tmp=gcd(max(ys[i],ys[j]),min(ys[i],ys[j]));
        wxy[i][reff[tmp]]=(wxy[i][reff[tmp]]+wxy[i-1][j]*(_l)(p2[cnt[ys[i]]]-1))%md;
        wxy[i][j]=(wxy[i-1][j]+wxy[i][j])%md;
    }
    for(i=1;i<=ys[0];++i)for(j=1;j<=ys[0];++j)if(ys[i]%ys[j]==0)an[i]=(an[i]+wxy[ys[0]][j])%md;
    while(q--){
        int x;scanf("%d",&x);x=gcd(max(x,p),min(x,p));
        printf("%lld\n",an[reff[x]]);
    }
}

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325098820&siteId=291194637