• bzoj2287 [POJ Challenge]消失之物


    传送门

    这么一道水题我还用各种麻烦的方法去做……这人没救了

    看在这题做法挺多的份上,我就都写写好了……

     

    1.CDQ分治

    这个做法是我想到的……因为受到了Eden的新背包问题的启发……

    定义solve(l,r)表示删除编号在[l,r]的物品并计算其DP数组,显然这个是可以折半往下递归的,用没删掉的那一半更新一下DP数组并带着DP数组递归下去即可。

    T(n)=2T(n/2)+O(nm),解得T(n)=O(nmlogn),并且比O(nm)的做法慢不了多少。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 const int maxn=2010;
     6 void CDQ(int,int,int);
     7 int n,m,w[maxn],f[15][maxn]={{0}};
     8 int main(){
     9     scanf("%d%d",&n,&m);
    10     for(int i=1;i<=n;i++)scanf("%d",&w[i]);
    11     f[0][0]=1;
    12     CDQ(1,n,0);
    13     return 0;
    14 }
    15 void CDQ(int l,int r,int k){
    16     if(l==r){
    17         for(int i=1;i<=m;i++)printf("%d",f[k][i]);
    18         printf("
    ");
    19         return;
    20     }
    21     int mid=(l+r)>>1;
    22     copy(f[k],f[k]+m+1,f[k+1]);
    23     for(int i=mid+1;i<=r;i++)for(int j=m;j>=w[i];j--){
    24         f[k+1][j]+=f[k+1][j-w[i]];
    25         if(f[k+1][j]>=10)f[k+1][j]%=10;
    26     }
    27     CDQ(l,mid,k+1);
    28     copy(f[k],f[k]+m+1,f[k+1]);
    29     for(int i=l;i<=mid;i++)for(int j=m;j>=w[i];j--){
    30         f[k+1][j]+=f[k+1][j-w[i]];
    31         if(f[k+1][j]>=10)f[k+1][j]%=10;
    32     }
    33     CDQ(mid+1,r,k+1);
    34 }
    View Code

     

    2.FFT

    好吧表示这个做法是lrd一开始想的……然而他并不会FFT

    定义f[i][j]表示用前i个物品凑出j的方案数,g[i][j]表示用后i个物品凑出j的方案数,h[i][j]表示去掉i后凑出j的方案数,显然有

    egin{align}h[i][j]=sum_{k=0}^j{f[i-1][k]*g[i+1][j-k]}end{align}

    可以发现这就是个裸卷积,FFT加速即可,复杂度显然是O(nmlogn),然而常数大如狗,跑的比CDQ分治慢到不知哪里去了……

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<cmath>
     4 #include<algorithm>
     5 using namespace std;
     6 const int maxn=2010;
     7 const double pi=acos(-1.0),eps=5e-3;
     8 struct Complex{
     9     double a,b;
    10     Complex(double a=0.0,double b=0.0):a(a),b(b){}
    11     Complex operator+(const Complex &x)const{return Complex(a+x.a,b+x.b);}
    12     Complex operator-(const Complex &x)const{return Complex(a-x.a,b-x.b);}
    13     Complex operator*(const Complex &x)const{return Complex(a*x.a-b*x.b,a*x.b+b*x.a);}
    14     Complex &operator*=(const Complex &x){return *this=*this*x;}
    15 }A[maxn<<2],B[maxn<<2];
    16 void FFT(Complex*,int,int);
    17 int n,m,N=1,w[maxn],f[maxn][maxn],g[maxn][maxn];
    18 int main(){
    19     scanf("%d%d",&n,&m);
    20     while(N<=m)N<<=1;N<<=1;
    21     f[0][0]=1;
    22     for(int i=1;i<=n;i++){
    23         scanf("%d",&w[i]);
    24         copy(f[i-1],f[i-1]+m+1,f[i]);
    25         for(int j=m;j>=w[i];j--){
    26             f[i][j]+=f[i-1][j-w[i]];
    27             if(f[i][j]>=10)f[i][j]%=10;
    28         }
    29     }
    30     g[n+1][0]=1;
    31     for(int i=n;i;i--){
    32         copy(g[i+1],g[i+1]+m+1,g[i]);
    33         for(int j=m;j>=w[i];j--){
    34             g[i][j]+=g[i+1][j-w[i]];
    35             if(g[i][j]>=10)g[i][j]%=10;
    36         }
    37     }
    38     for(int i=1;i<=n;i++){
    39         fill(A,A+N,Complex(0.0,0.0));
    40         for(int j=0;j<=m;j++)A[j].a=f[i-1][j];
    41         fill(B,B+N,Complex(0.0,0.0));
    42         for(int j=0;j<=m;j++)B[j].a=g[i+1][j];
    43         FFT(A,N,1);
    44         FFT(B,N,1);
    45         for(int j=0;j<N;j++)A[j]*=B[j];
    46         FFT(A,N,-1);
    47         for(int j=1;j<=m;j++)printf("%d",(int)(A[j].a+eps)%10);
    48         printf("
    ");
    49     }
    50     return 0;
    51 }
    52 void FFT(Complex *A,int n,int tp){
    53     for(int i=1,j=0,k;i<n-1;i++){
    54         k=n;
    55         do j^=(k>>=1);while(j<k);
    56         if(i<j)swap(A[i],A[j]);
    57     }
    58     for(int k=2;k<=n;k<<=1){
    59         Complex wn(cos(-tp*2*pi/k),sin(-tp*2*pi/k));
    60         for(int i=0;i<n;i+=k){
    61             Complex w(1.0,0.0);
    62             for(int j=0;j<(k>>1);j++,w*=wn){
    63                 Complex a=A[i+j],b=w*A[i+j+(k>>1)];
    64                 A[i+j]=a+b;
    65                 A[i+j+(k>>1)]=a-b;
    66             }
    67         }
    68     }
    69     if(tp<0)for(int i=0;i<n;i++)A[i].a/=n;
    70 }
    View Code

     

    3.DP(想不到更好的称呼了……)

    这个做法是lrz告诉我的……我怎么这么愚蠢连这都想不到

    首先把用所有物品凑出j的方案数全都求出来,因为填满j的方案数不受物品顺序影响,而把第i个物品放到最后之后是可以把DP方程逆变换回去得到删掉i之后凑出j的方案数,然后就果断O(nm)了……咦怎么才比多一个logCDQ分治快这么一点

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 const int maxn=2010;
     6 int n,m,w[maxn],f[maxn]={0},g[maxn];
     7 int main(){
     8     scanf("%d%d",&n,&m);
     9     f[0]=1;
    10     for(int i=1;i<=n;i++){
    11         scanf("%d",&w[i]);
    12         for(int j=m;j>=w[i];j--){
    13             f[j]+=f[j-w[i]];
    14             if(f[j]>=10)f[j]%=10;
    15         }
    16     }
    17     for(int i=1;i<=n;i++){
    18         copy(f,f+m+1,g);
    19         for(int j=w[i];j<=m;j++){
    20             g[j]-=g[j-w[i]];
    21             if(g[j]<0)g[j]+=10;
    22         }
    23         for(int j=1;j<=m;j++)printf("%d",g[j]);
    24         printf("
    ");
    25     }
    26     return 0;
    27 }
    View Code

    这个故事告诉我们一个道理:学东西不要学傻了……

  • 相关阅读:
    poj 3304 Segments 直线 线段求交
    poj 1077 Eight 八数码 A*算法
    UESTC 1447 Area 凸包+旋转卡壳 求最大四边形面积
    ACM计算几何题目推荐(第二期)
    poj 2398 Toy Storage 叉乘
    ACM计算几何题目推荐 (第一期)
    (转载)Telnet协议详解及使用C# 用Socket 编程来实现Telnet协议
    jquery 表情编辑器
    (读书笔记)Asp.net Mvc 与WebForm 混合开发
    (转载)精简说明C#最基本的Socket编程示例
  • 原文地址:https://www.cnblogs.com/hzoier/p/6410286.html
Copyright © 2020-2023  润新知