BZOJ1002: [FJOI2007]轮状病毒 (DP)
标准做法似乎应该是计算生成树数量的基尔霍夫矩阵之类的..
我看到的做法是一个神奇的高精度dp,当然以后这个blahblahblah矩阵还是要搞一下。。
View Code
这个dp的原理就是把环拆成一条含特定点的链和剩下部分(可用dp解决),这样就避免了环具有的一些dp不好解决的奇怪判定.
非常神奇
%想出这个办法的dalao
附上非常不走心的非常丑的自己的代码..
1 #include<cmath> 2 #include<cstdio> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 #include<queue> 7 using namespace std; 8 int n; 9 int f[110][2][35]={};//1 到i的单独一段都和中间连上了 0 到i的单独一段没有和中间连上 10 int ans[35]={}; 11 int z[35]={}; 12 int a[35]={}; 13 int b[35]={}; 14 int w=0; 15 void plu(){//a+b存z 16 int e=0; 17 for(int i=1;i<=30;i++){ 18 e=a[i]+b[i]+e; 19 z[i]=e%10000; 20 e/=10000; 21 } 22 } 23 void mul(){//b*w存z 24 int e=0; 25 for(int i=1;i<=30;i++){ 26 e=w*b[i]+e; 27 z[i]=e%10000; 28 e/=10000; 29 } 30 } 31 int main(){ 32 scanf("%d",&n); 33 f[1][1][1]=f[1][0][1]=1; 34 f[0][1][1]=1; 35 for(int i=2;i<=n;i++){ 36 for(int j=1;j<=30;j++){ 37 a[j]=f[i-1][0][j]; 38 b[j]=f[i-1][1][j]; 39 } 40 plu(); 41 for(int j=1;j<=30;j++){ 42 f[i][0][j]=z[j]; 43 z[j]=0; 44 } 45 46 w=2; 47 mul(); 48 for(int j=1;j<=30;j++){ 49 b[j]=z[j]; 50 z[j]=0; 51 } 52 plu(); 53 for(int j=1;j<=30;j++){ 54 f[i][1][j]=z[j]; 55 z[j]=0; 56 } 57 } 58 for(int i=1;i<=n;i++){ 59 w=i*i; 60 for(int j=1;j<=30;j++){ 61 b[j]=f[n-i][1][j]; 62 a[j]=ans[j]; 63 } 64 mul(); 65 for(int j=1;j<=30;j++){ 66 b[j]=z[j]; 67 z[j]=0; 68 } 69 plu(); 70 for(int j=1;j<=30;j++){ 71 ans[j]=z[j]; 72 z[j]=0; 73 } 74 } 75 int f=0; 76 for(int i=30;i>=1;i--){ 77 if(ans[i]!=0&&f==0){ 78 f=1; 79 printf("%d",ans[i]); 80 continue; 81 } 82 if(f){ 83 if(ans[i]>999){ 84 cout<<ans[i]; 85 } 86 else if(ans[i]>99){ 87 cout<<0<<ans[i]; 88 } 89 else if(ans[i]>9){ 90 cout<<0<<0<<ans[i]; 91 } 92 else{ 93 cout<<0<<0<<0<<ans[i]; 94 } 95 } 96 } 97 cout<<endl; 98 return 0; 99 }