D - Circular Coloring(dp j个数分成i段)
原题: http://acm.hdu.edu.cn/showproblem.php?pid=6279题意:有n个0,m个1,组成一个环(循环同构算不同的),连续的0或1串的贡献为其长度,一个串的值为所有贡献的乘积。问所有情况的值之和。解析:假设已经得出将j个数分成i段的答案(不是环),记为dp[i][j]dp[i][j]dp[i][j]。显然在环中0和1的段数相同,所以ans=∑i=1m...
原题: http://acm.hdu.edu.cn/showproblem.php?pid=6279
题意:
有n个0,m个1,组成一个环(循环同构算不同的),连续的0或1串的贡献为其长度,一个串的值为所有贡献的乘积。问所有情况的值之和。
解析:
假设已经得出将j个数分成i段的答案(不是环),记为 d p [ i ] [ j ] dp[i][j] dp[i][j]。
显然在环中0和1的段数相同,所以 a n s = ∑ i = 1 m i n ( n , m ) ( d p [ i ] [ n ] + d p [ i ] [ m ] ) ans=\sum_{i=1}^{min(n,m)}(dp[i][n]+dp[i][m]) ans=∑i=1min(n,m)(dp[i][n]+dp[i][m])。
但是现在在环上,如果循环同构只算一次,那么考虑i段的情况会多记录i-1次(123,231,321),再考虑两种和到一起后可以旋转n+m次(循环同构算不同的),所以变为: a n s = ∑ i = 1 m i n ( n , m ) ( d p [ i ] [ n ] + d p [ i ] [ m ] ) ∗ ( n + m ) i ans=\sum_{i=1}^{min(n,m)}\dfrac{(dp[i][n]+dp[i][m])*(n+m)}{i} ans=∑i=1min(n,m)i(dp[i][n]+dp[i][m])∗(n+m)。
再考虑dp的求解。
显然 d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] + 2 d p [ i − 1 ] [ j − 2 ] + 3 d p [ i − 1 ] [ j − 3 ] . . . dp[i][j]=dp[i-1][j-1]+2dp[i-1][j-2]+3dp[i-1][j-3]... dp[i][j]=dp[i−1][j−1]+2dp[i−1][j−2]+3dp[i−1][j−3]...
而 d p [ i ] [ j − 1 ] = d p [ i − 1 ] [ j − 2 ] + 2 d p [ i − 1 ] [ j − 3 ] . . . dp[i][j-1]=dp[i-1][j-2]+2dp[i-1][j-3]... dp[i][j−1]=dp[i−1][j−2]+2dp[i−1][j−3]...
所以 d p [ i ] [ j ] = d p [ i ] [ j − 1 ] + ( d p [ i − 1 ] [ j − 1 ] + d p [ i − 1 ] [ j − 2 ] + d p [ i − 1 ] [ j − 3 ] . . . ) dp[i][j]=dp[i][j-1]+(dp[i-1][j-1]+dp[i-1][j-2]+dp[i-1][j-3]...) dp[i][j]=dp[i][j−1]+(dp[i−1][j−1]+dp[i−1][j−2]+dp[i−1][j−3]...)
用一个前缀和就可以实现O(1)维护。
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const LL mod=1e9+7;
LL dp[5009][5009];
LL sum[2][5009];
LL inv[5009];
int main(){
inv[1]=1;
for(int i=2;i<=5000;i++)inv[i]=inv[mod%i]*(mod-mod/i)%mod;
dp[1][1]=1;
int ff=0;
sum[ff][1]=1;
for(int i=2;i<=5000;i++)
dp[1][i]=i,sum[ff][i]=(sum[ff][i-1]+dp[1][i])%mod;
for(int i=2;i<=5000;i++){
dp[i][i]=1;
sum[!ff][i]=1;
for(int j=i+1;j<=5000;j++){
dp[i][j]=(dp[i][j-1]+sum[ff][j-1])%mod;
sum[!ff][j]=(sum[!ff][j-1]+dp[i][j])%mod;
}
ff=!ff;
}
int n,m;
while(cin>>n>>m){
LL ans=0;
for(int i=1;i<=min(n,m);i++){
ans+=(dp[i][n]*dp[i][m])%mod*inv[i]%mod;
}
ans%=mod;
printf("%lld\n",(ans*(n+m)%mod+mod)%mod );
}
}
更多推荐



所有评论(0)