题意:
n个有标号的球围成一个圈。每个球有两种颜色可以选择黑或白染色。问有多少种方案使得没有出现连续白球7个或连续黑球7个?
思路:
如果出现连续的8,9...个球同色,那么也必定含有7个同色。需要统计两部分,第一部分是将n个球看成一个序列,在不允许出现连续7个同色球的情况下,统计其可能出现的所有方案数。第二部分是,在第一部分中统计到的,有可能在一个圈的接口处可能出现超过6个球同色的,那么只需要再统计一下这一情况的方案数。问题在于这里。
序列上肯定不会超过6个同色,所以环的头尾加起来最多有12个同色球,即序列前6个,序列后6个。但是如果n<=12的话,还不会出现环接口处12个同色的情况,需要分类讨论。假设n=8,那么最多可能出现7个同色(根据第一部分的假设),若n=9,最多可能出现8个同色....若n=13,最多可能出现12个同色。先假设序列A={7,8,9,10,11,12}。
如何求第二部分?假如n=8,那么最多可能出现7个连色,那么就先假设前7个球都是黑色,剩下1个球,只能是白色了,所以方案数为1。但是前7个球可能是白色的,而剩下的1球是黑色的,这只需要将前面的方案数乘以2就行了。而这7个连色的球还可能在环上的不同位置出现,所以还得再乘以(13-7)。其他的大概也是这样推的,只是部分处理可能不同。
1 //#include <bits/stdc++.h> 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5 #include <cmath> 6 #include <map> 7 #include <algorithm> 8 #include <vector> 9 #include <iostream> 10 #define pii pair<int,int> 11 #define INF 0x7f3f3f3f 12 #define LL long long 13 #define ULL unsigned long long 14 using namespace std; 15 const double PI = acos(-1.0); 16 const int M=2015; 17 int cur, dp[2][1<<6], ans[100010], up=1<<6, mod=1<<5; 18 19 void DP(int n) 20 { 21 for(int i=1; i<=n; i++) 22 { 23 ans[0]=ans[i]=0; 24 cur^=1; 25 memset(dp[cur], 0, sizeof(dp[cur])); 26 for(int s=0,t,v; s<up; s++) 27 { 28 v=dp[cur^1][s]; 29 t=(s&(mod-1))<<1; //取低5位 30 31 if(s+1==up) //6黑 32 { 33 dp[cur][t]+=v; 34 ans[i]+=v; //只取白色结尾的 35 ans[0]+=v; 36 } 37 else if(s==0) //6白 38 { 39 dp[cur][t+1]+=v; 40 ans[0]+=v; 41 } 42 else 43 { 44 dp[cur][t]+=v; 45 dp[cur][t+1]+=v; 46 ans[i]+=v; 47 ans[0]+=v+v; 48 } 49 50 dp[cur][t]%=M; 51 dp[cur][t+1]%=M; 52 ans[i]%=M; 53 ans[0]%=M; 54 } 55 } 56 } 57 58 int cal(int n) 59 { 60 if(n<7) return 1<<n; 61 if(n==7) return 126; 62 63 memset(dp[cur=0],0,sizeof(dp[cur])); 64 dp[cur][up-1]=1; //默认前7个全黑,但是状态只记6位 65 DP(n); 66 int ans1=ans[0]*2%M, ans2=0; 67 for(int k=7; k<=12; k++) //最多可能取到6+6=12个同颜色的 68 if(n-k>0) 69 ans2=(ans2+ans[n-k]*2*(13-k))%M; //枚举13-k个位置 70 71 return (ans1+M-ans2)%M; 72 } 73 74 75 int main() 76 { 77 //freopen("input.txt","r",stdin); 78 int n, t, Case=0; 79 scanf("%d",&t); 80 while(t--) 81 { 82 scanf("%d",&n); 83 printf("Case #%d: %d ",++Case,cal(n)); 84 } 85 return 0; 86 }