zoukankan      html  css  js  c++  java
  • CodeForces 632E Thief in a Shop

    题意:给你n种物品,每种无限个,问恰好取k个物品能组成哪些重量.n<=1000,k<=1000,每种物品的重量<=1000.

    我们搞出选取一种物品时的生成函数,那么只要对这个生成函数求k次幂就可以了.结果会很大所以我们可以在模意义下NTT来搞.然而会有一个问题,就是算出来的系数可能恰好是模数的倍数,比如说我们只用998244353就会WrongAnswer on test 20.然后我试了和异化多肽的模数1005060097一块来,然后,WrongAnswer on test 5…Excuse me? 然后看数据,k=1000,物品重量也比较大,分解一下1005060096,发现是2^19*27*71,然后我意识到了:这道题最大需要做最高次数2^20的NTT…然后枚举出了几个2^22*k+1的质数做模数…过了…

    以下是枚举出来的一些模数和原根,均为2^22*k+1的形式(不保证k为奇数)

    104857601 3

    113246209 7

    138412033 5

    155189249 6

    163577857 23

    167772161 3

    230686721 6

    377487361 7

    415236097 5

    469762049 3

    595591169 3

    645922817 3

    666894337 5

    683671553 3

    754974721 11

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int mod,rt;
    int qpow(int a,int x){int ans=1;for(;x;x>>=1,a=a*1ll*a%mod)if(x&1)ans=ans*1ll*a%mod;return ans;}
    void ntt(int *a,int n,int sign){
      for(int i=1,j=0,k;i<n;++i){
        k=n;do j^=(k>>=1);while(j<k);if(i<j)swap(a[i],a[j]);
      }
      for(int j=2;j<=n;j<<=1){
        int m=j>>1;long long wn=qpow(rt,(mod-1+sign*(mod-1)/j));;
        for(int *p=a;p!=a+n;p+=j){
          long long w=1;
          for(int k=0;k<m;++k,w=w*wn%mod){
        long long t=w*p[m+k]%mod;p[m+k]=(p[k]-t+mod)%mod;p[k]=(p[k]+t)%mod;
          }
        }
      }
      if(sign==-1){
        long long inv=qpow(n,mod-2);for(int i=0;i<n;++i)a[i]=a[i]*inv%mod;
      }
    }
    const int maxn=1048576*4;
    int a[maxn],w[maxn];
    int ans[maxn];
    int N; int n,k;
    void NTT(int MOD,int RT){
      mod=MOD;rt=RT;memset(a,0,sizeof(a));
      for(int i=1;i<=n;++i)a[w[i]]=1;
      ntt(a,N,1);
      for(int i=0;i<N;++i)a[i]=qpow(a[i],k);
      ntt(a,N,-1);//printf("%d
    ",ans[1]);
      for(int i=0;i<N;++i)if(a[i])ans[i]=1;
    }
    int main(){
      scanf("%d%d",&n,&k);
      int Max=0;
      for(int i=1;i<=n;++i){scanf("%d",&w[i]);if(w[i]>Max)Max=w[i];}
      N=1;
      while(N<=Max*k)N<<=1;
      //printf("%d
    ",ans[0]);
      NTT(998244353,3);NTT(163577857,23);NTT(415236097,5);
      for(int i=0;i<N;++i)if(ans[i])printf("%d ",i);
      return 0;
    }
  • 相关阅读:
    我爬了《流浪地球》十万个短评得出以下结论
    Activiti开发案例之代码生成工作流图片
    Activiti开发案例之activiti-app工作流导出图片
    用MySQL语法建 一个学生表,包括学生姓名、性别、年龄、班级信息。
    事务是什么,以及事务四个特性
    精选30道Java笔试题解答
    父类和子类的构造方法的调用顺序
    Java的修饰符
    volatile修饰符
    Java中普通代码块,构造代码块,静态代码块区别及代码示例
  • 原文地址:https://www.cnblogs.com/liu-runda/p/6547008.html
Copyright © 2011-2022 走看看