zoukankan      html  css  js  c++  java
  • HAOI2018 奇怪的背包

    传送门

    这道题很神奇……
    首先我们考虑只有一个物品的情况。通过观察发现,只要(gcd(v,P) | w)那么就可以,否则就不行。
    然后推广到多个物品的时候,我们发现仍然是成立的,就是对于多个物品取gcd。
    我们可以发现每个物品的价值v和(gcd(v,P))是完全等价的,可以直接变成(gcd(v,P)),那么我们现在所有物品的价值就都是P的因子了。
    于是我们考虑DP。令(dp[i][j])表示选取了P的i个因子,这i个因子的gcd是p的第j个因子的方案数。那么转移方程就是(dp[i][j] = dp[i-1][j] + sum_{gcd(a[i],a[j]) = a[k]}dp[i-1][k] * 2^{s[i]}-1) ,其中s[i]表示第i个因子出现的次数。出现x次的话就有(2^x-1)种情况被选中,少的一种是全不选的。
    这样的话,令P的因子数为C,对于每次询问,答案就是(sum_{a[i] | w}dp[n][i]),但是这个复杂度是(O(qC))的,有可能会超时。
    考虑到(a[i] | w,a[i] | P),那么显然(a[i] | gcd(P,w)),也就是某一个P的因子。
    对于这个嘛,我们在DP之后就可以预处理出(g[i] = sum_{a[j] | i}dp[n][j]),这样就可以(O(1))处理每一次询问,然后就可以(O(q))通过这道题了……

    不知道为什么我不用滚动数组就一直在错……用滚动数组就过了……

    // luogu-judger-enable-o2
    #include<bits/stdc++.h>
    #define rep(i,a,n) for(int i = a;i <= n;i++)
    #define per(i,n,a) for(int i = n;i >= a;i--)
    #define enter putchar('
    ')
    #define pr pair<int,int>
    #define fi first
    #define sc second
    
    using namespace std;
    typedef long long ll;
    const int M = 4005;
    const int N = 1000005;
    const int mod = 1e9+7;
    
    int read()
    {
        int ans = 0,op = 1;char ch = getchar();
        while(ch < '0' || ch > '9') {if(ch == '-') op = -1;ch = getchar();}
        while(ch >= '0' && ch <= '9') ans *= 10,ans += ch - '0',ch = getchar();
        return ans * op;
    }
    
    int n,q,P,v[N],po[N],tot[N],dp[8005][2005],g[8005],cnt,num[M],x,now;
    int gcd(int a,int b){return b ? gcd(b,a%b) : a;}
    int inc(int a,int b){return (a+b) % mod;}
    int mul(int a,int b){return 1ll * a * b % mod;}
    
    void init()
    {
       po[1] = 2;
       rep(i,2,n) po[i] = mul(po[i-1],2);
       rep(i,1,n) po[i] = inc(po[i],mod-1);
       rep(i,1,sqrt(P))
       {
          if(P % i == 0)
          {
         num[++cnt] = i;
         if(i * i != P) num[++cnt] = P / i;
          }
       }
       sort(num+1,num+1+cnt);
       rep(i,1,n)
       {
          int cur = lower_bound(num+1,num+1+cnt,v[i]) - num;
          tot[cur]++;
       }
       rep(i,1,cnt)
       {
          if(!tot[i]) continue;
          now ^= 1;
          rep(j,1,cnt) dp[now][j] = dp[now^1][j];
          rep(j,1,cnt)
          {
         if(!dp[now^1][j]) continue;
         int cur = gcd(num[i],num[j]);
         int pos = lower_bound(num+1,num+1+cnt,cur) - num;
         dp[now][pos] = inc(dp[now][pos],mul(dp[now^1][j],po[tot[i]]));
          }
          dp[now][i] = inc(dp[now][i],po[tot[i]]);
       }
       rep(i,1,cnt)
          rep(j,1,i) if(num[i] % num[j] == 0) g[i] = inc(g[i],dp[now][j]);
    }
    
    int main()
    {
       n = read(),q = read(),P = read();
       rep(i,1,n) v[i] = read(),v[i] = gcd(v[i],P);
       init();
       while(q--)
       {
          x = read(),x = gcd(x,P);
          int cur = lower_bound(num+1,num+1+cnt,x) - num;
          printf("%d
    ",g[cur]);
       }
       return 0;
    }
    
    
  • 相关阅读:
    ionic3-ng4学习见闻--(aot方式打包问题解决方案)
    ionic3-ng4学习见闻--(轮播图完美方案)
    ionic3-ng4学习见闻--(多语言方案)
    死也要上npm 而不是cnpm苟且偷生
    2017埙箫简谱清单分享(附音频Demo)
    《好久不见》(Cover 陈奕迅)箫声远 洞箫
    React-onsenui之RouterNavigator组件解读
    基于3ds Max的游戏建模方案
    重拾SQL——从无到有
    重拾SQL——表中索值
  • 原文地址:https://www.cnblogs.com/captain1/p/10603709.html
Copyright © 2011-2022 走看看