[关闭]
@ysner 2018-06-07T13:31:15.000000Z 字数 3831 阅读 1897

序列问题

DP 高精度


题面

现有一个长度为的序列,找出两个非空的集合
这两个集合要满足以下的条件:

询问一共有多少对这样的集合

解析

直接设表前个数中 已取数 异或和 为的方案数。
同理。
然后枚举分割点和相等值统计答案。
注意一下开始分割点要放在取了的数上,否则会计重。

  1. #include<iostream>
  2. #include<cmath>
  3. #include<cstring>
  4. #include<cstdio>
  5. #include<cstdlib>
  6. #include<algorithm>
  7. #define ll long long
  8. #define re register
  9. #define il inline
  10. #define fp(i,a,b) for(re int i=a;i<=b;i++)
  11. #define fq(i,a,b) for(re int i=a;i>=b;i--)
  12. using namespace std;
  13. const int N=1024;
  14. int n,a[N];
  15. ll lt[1200][1200],rt[1200][1200][2],ans;
  16. il ll gi()
  17. {
  18. re ll x=0,t=1;
  19. re char ch=getchar();
  20. while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
  21. if(ch=='-') t=-1,ch=getchar();
  22. while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
  23. return x*t;
  24. }
  25. il void wri(re int x)
  26. {
  27. if(x<0) putchar('-'),x=-x;
  28. if(x>9) wri(x/10);
  29. putchar(x%10+'0');
  30. }
  31. int main()
  32. {
  33. freopen("sequence.in","r",stdin);
  34. freopen("sequence.out","w",stdout);
  35. n=gi();
  36. fp(i,1,n) a[i]=gi();
  37. fp(i,1,n) lt[i][a[i]]=1,rt[i][a[i]][1]=1;
  38. fp(i,1,n)
  39. fp(j,0,N)
  40. {
  41. lt[i][j^a[i]]+=lt[i-1][j];
  42. lt[i][j]+=lt[i-1][j];
  43. }
  44. fq(i,n,1)
  45. fp(j,0,N)
  46. {
  47. rt[i][j&a[i]][1]+=rt[i+1][j][1]+rt[i+1][j][0];
  48. rt[i][j][0]+=rt[i+1][j][1]+rt[i+1][j][0];
  49. }
  50. fp(i,1,n)
  51. fp(j,0,N)
  52. ans+=lt[i-1][j]*rt[i][j][1];
  53. printf("%lld\n",ans);
  54. fclose(stdin);
  55. fclose(stdout);
  56. return 0;
  57. }

复杂度

注意到的值可能以的比例呈现。。。
所以我们需要高精。。。
然而我们发现强行高精乘效率很低。
于是我们要把方程式转化一下。
表示第个数中,已取数"and和"()或"xor和""and和")为的方案数。
应选择倒推,这样最后的合法情况中一定为





(注意短式不能与长式合并,因长式中第二位取值受到限制
答案在中。
这样只用高精加即可。
同时,如果把数组转为高精,就需要滚动以省空间。
滚动前:

  1. n=gi();
  2. fp(i,1,n) a[i]=gi();
  3. fp(i,1,n) dp[i][a[i]][0]=1;
  4. fq(i,n,1)
  5. fp(j,0,1023)
  6. {
  7. dp[i][j&a[i]][0]+=dp[i+1][j][0];
  8. dp[i][j^a[i]][1]+=dp[i+1][j][1]+dp[i+1][j][0];
  9. dp[i][j][0]+=dp[i+1][j][0];
  10. dp[i][j][1]+=dp[i+1][j][1];
  11. }
  12. printf("%lld\n",dp[1][0][1]);

滚动后:
注意到数组进行转移前要先集体赋值,否则可能会加上上两次的方案。并且赋值为改为

  1. n=gi();
  2. fp(i,1,n) a[i]=gi();
  3. fq(i,n,1)
  4. {
  5. re int now=i&1,las=(i&1)^1;
  6. fp(j,0,N-1) dp[now][j][0]=dp[las][j][0],dp[now][j][1]=dp[las][j][1];
  7. dp[now][a[i]][0]++;
  8. fp(j,0,N-1)
  9. {
  10. dp[now][j&a[i]][0]+=dp[las][j][0];
  11. dp[now][j^a[i]][1]+=dp[las][j][1]+dp[las][j][0];
  12. }
  13. }
  14. cout<<dp[1][0][1]<<endl;

更加毒瘤

发现出题人很卡复杂度,高精运算复杂度过高还是会
于是我们需要压位。
并且如果高精数位数很大速度也很慢!!!
于是压九位,高精数开五十位即可。
注意一下输出方式。

  1. #include<iostream>
  2. #include<cmath>
  3. #include<cstring>
  4. #include<cstdio>
  5. #include<cstdlib>
  6. #include<algorithm>
  7. #define ll long long
  8. #define re register
  9. #define il inline
  10. #define fp(i,a,b) for(re int i=a;i<=b;i++)
  11. #define fq(i,a,b) for(re int i=a;i>=b;i--)
  12. using namespace std;
  13. const int N=1024;
  14. int n,a[N];
  15. class BigInteger
  16. {
  17. public:
  18. int sz,num[50];
  19. BigInteger(){sz=1;memset(num,0,sizeof(num));}
  20. void print()
  21. {
  22. fq(i,sz,1) if(i^sz) printf("%09d",num[i]);else printf("%d",num[i]);
  23. puts("");
  24. }
  25. }dp[2][1200][2],ysn;
  26. BigInteger operator + (BigInteger A,BigInteger B)
  27. {
  28. BigInteger Ans;
  29. re int s=max(A.sz,B.sz);
  30. Ans.sz=s;
  31. fp(i,1,s) Ans.num[i]=A.num[i]+B.num[i];
  32. fp(i,1,s)
  33. if(Ans.num[i]>999999999)
  34. {
  35. Ans.num[i+1]+=Ans.num[i]/1000000000;
  36. Ans.num[i]=Ans.num[i]%1000000000;
  37. }
  38. if(Ans.num[s+1]) ++Ans.sz;
  39. return Ans;
  40. }
  41. il ll gi()
  42. {
  43. re ll x=0,t=1;
  44. re char ch=getchar();
  45. while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
  46. if(ch=='-') t=-1,ch=getchar();
  47. while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
  48. return x*t;
  49. }
  50. il void wri(re int x)
  51. {
  52. if(x<0) putchar('-'),x=-x;
  53. if(x>9) wri(x/10);
  54. putchar(x%10+'0');
  55. }
  56. int main()
  57. {
  58. freopen("sequence.in","r",stdin);
  59. freopen("sequence.out","w",stdout);
  60. n=gi();ysn.num[1]=1;ysn.sz=1;
  61. fp(i,1,n) a[i]=gi();
  62. fq(i,n,1)
  63. {
  64. re int now=i&1,las=(i&1)^1;
  65. fp(j,0,N-1) dp[now][j][0]=dp[las][j][0],dp[now][j][1]=dp[las][j][1];
  66. dp[now][a[i]][0]=dp[now][a[i]][0]+ysn;
  67. fp(j,0,N-1)
  68. {
  69. dp[now][j&a[i]][0]=dp[now][j&a[i]][0]+dp[las][j][0];
  70. dp[now][j^a[i]][1]=dp[now][j^a[i]][1]+dp[las][j][1]+dp[las][j][0];
  71. }
  72. }
  73. dp[1][0][1].print();
  74. fclose(stdin);
  75. fclose(stdout);
  76. return 0;
  77. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注