您的位置:首页 > 大数据 > 人工智能

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

#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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: