Aizu 2164 CSUOJ 1436 Revenge of the Round Table
2014-05-26 12:08
387 查看
dp套一个burnside的壳子
核心还是dp
dp[i]表示有i个循环节时的染色方案数
注意在dp的时候,不需要考虑重构的问题
因为burnside会解决重构的问题
dpA[i][j]表示以A开头,长度为i,结尾为j个A的合法方案数
dpB[i][j]表示以B开头,长度为i,结尾为j个A的合法方案数
接下来我们用dpA,dpB来计算dp[i]
显然对于所有的dpB[i][1~k]都是满足dp[i]的
因为它表示以B开头,以A结尾的染色方案,且结尾没有超过k个
另外还有一部分就是以A开头的了
假设我们在整个串的最前面放p个A(p<=k)
在这串A后面放以B开头,以A结尾的串(也就是dpB表示的串)
那么结尾的A不能超过k-p个
也就是说,当我在整个串的最前面放p个A时,所有的
dpB[i-p][0],dpB[i-p][1],dpB[i-p][2]............dpB[i-p][k-p]
都是合法的,这里可以直接用一个前缀和来处理。
计算出dp[i]之后,剩下的就是套一个burnside的壳子了
注意n<=k的时候的处理,最后结果要+2
View Code
核心还是dp
dp[i]表示有i个循环节时的染色方案数
注意在dp的时候,不需要考虑重构的问题
因为burnside会解决重构的问题
dpA[i][j]表示以A开头,长度为i,结尾为j个A的合法方案数
dpB[i][j]表示以B开头,长度为i,结尾为j个A的合法方案数
接下来我们用dpA,dpB来计算dp[i]
显然对于所有的dpB[i][1~k]都是满足dp[i]的
因为它表示以B开头,以A结尾的染色方案,且结尾没有超过k个
另外还有一部分就是以A开头的了
假设我们在整个串的最前面放p个A(p<=k)
在这串A后面放以B开头,以A结尾的串(也就是dpB表示的串)
那么结尾的A不能超过k-p个
也就是说,当我在整个串的最前面放p个A时,所有的
dpB[i-p][0],dpB[i-p][1],dpB[i-p][2]............dpB[i-p][k-p]
都是合法的,这里可以直接用一个前缀和来处理。
计算出dp[i]之后,剩下的就是套一个burnside的壳子了
注意n<=k的时候的处理,最后结果要+2
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 1010; const int mod = 1000003; typedef long long LL; int dpA[maxn][maxn],dpB[maxn][maxn],dp[maxn]; int n,k; LL ans,all; void DP(){ memset(dpA,0,sizeof(dpA)); memset(dpB,0,sizeof(dpB)); memset(dp,0,sizeof(dp)); int asum = 1,bsum = 0; if(k >= n){ k = n-1; all = 2; } dpA[1][1] = 1; dpB[1][1] = 0; for(int i = 2;i <= n;i++){ dpA[i][1] = bsum; dpB[i][1] = asum; swap(asum,bsum); for(int j = 2;j <= min(n,k);j++){ dpA[i][j] = dpA[i-1][j-1]; asum = (asum+dpA[i][j])%mod; dpB[i][j] = dpB[i-1][j-1]; bsum = (bsum+dpB[i][j])%mod; } } for(int i = 1;i <= n;i++){ for(int j = 1;j <= min(n,k);j++){ dp[i] += dpB[i][j]; dp[i] %= mod; } } for(int i = 1;i <= n;i++){ for(int j = 1;j < k;j++){ dpB[i][j+1] += dpB[i][j]; dpB[i][j+1] %= mod; } } for(int i = 1;i <= n;i++){ for(int p = 1;p <= min(i,k);p++){ dp[i] += dpB[i-p][k-p]; dp[i] %= mod; } } } int gcd(int a,int b){ return b == 0 ? a : gcd(b,a%b); } LL pow_mod(LL a,LL n){ LL ret = 1; while(n){ if(n&1) ret = ret*a%mod; n >>= 1; a = a*a%mod; } return ret; } int main() { while(scanf("%d%d",&n,&k) == 2){ ans = 0,all = 0; DP(); for(int i = 0;i < n;i++){ ans += 2*dp[gcd(i,n)]; ans %= mod; } ans = ans*pow_mod(n,mod-2)%mod; printf("%lld\n",(ans+all)%mod); } return 0; }
View Code
相关文章推荐
- POJ2942 Knights of the Round Table
- POJ 2942 Knights of the Round Table 点重连通分量+交叉染色判奇圈
- (挑战编程_13_3)The Knights Of The Round Table
- POJ 2942 Knights of the Round Table ★(点双连通分量+二分图判定)
- POJ 2942 Knights of the Round Table (奇圈+点双联通)
- POJ 2942 Knights of the Round Table ★(点双连通分量+二分图判定)
- POJ-2942 Knights of the Round Table 双连通分量[推荐]
- POJ-2942-Knights of the Round Table
- POJ 2942 Knights of the Round Table
- 【综合图论】PKU-2942-Knights of the Round Table
- PKU 2942 Knights of the Round Table - 无向图的块 判断奇圈
- poj 2942 Knights of the Round Table
- POJ 2492 Knights of the Round Table
- POJ2942-Knights of the Round Table
- UVA 10195 - The Knights Of The Round Table
- ★【双连通分量】【奇环判定】Knights of the Round Table
- pku2942 Knights of the Round Table
- Knights of the Round Table--POJ 2942
- The Knights of the Round Table
- poj2942点双连通奇圈-二分图判断Knights of the Round Table