标签:des style blog http io ar color os sp
/*题意:给出一个环,每个点是一个数字,取一个子串,使得拼接起来的数字是K的倍数。 由于K不大,暂且不考虑环的话,那么dp[i][j]表示以i结尾的,模K为j的有多少个子串。 那么sigma (dp[i][0])便是不考虑环的答案。 考虑环的话,不知道别人怎么写的,我感觉我的写法不是很复杂。 环和情况1 和n肯定是必选的,那么便是一个前缀为后缀,一个后缀为前缀拼接而成。 所以枚举某个前缀,求出前缀模K,那么枚举后缀模K的值,通过之前已经预处理过的dp值,便可以求出有多少个后缀满足为K的倍数。 但是这样可能后缀和前缀重叠了,所以我们枚举前缀的同时,依次记录后缀不同模值的个数。 随着前缀的增长,这些后缀都是和前缀重叠的。 */
5 7 9 6 4 2 8
5
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long int LL; const int maxn=50005; int dp[2][205]; int fac[maxn*4],l[maxn]; int cnt[205]; int pref[maxn],suff[maxn]; int a[maxn],N,K; int WE(int x) { if(x==0) return 1; int ret=0; while(x) { x/=10; ret++; } return ret; } int main() { while(scanf("%d%d",&N,&K)!=EOF) { /*******init***********/ memset(dp,0,sizeof(dp)); memset(cnt,0,sizeof(cnt)); fac[0]=1; for(int i=1;i<=(N<<2);i++) fac[i]=fac[i-1]*10%K; /**********************/ for(int i=1;i<=N;i++) { scanf("%d",a+i); l[i]=WE(a[i]); } dp[1][a[1]%K]=1; LL ans=dp[1][0]; for(int i=2;i<=N;i++) { for(int j=0;j<K;j++) dp[i&1][j]=0; dp[i&1][a[i]%K]++; for(int j=0;j<K;j++) { int r=(j*fac[l[i]]+a[i])%K; dp[i&1][r]+=dp[(i-1)&1][j]; } ans+=dp[i&1][0]; } /************环型DP**************/ pref[0]=0; for(int i=1;i<=N;i++) pref[i]=(pref[i-1]*fac[l[i]]+a[i])%K; int len=0; suff[N+1]=0; for(int i=N;i>=1;i--) { suff[i]=(a[i]*fac[len]+suff[i+1])%K; len+=l[i]; } len=0; for(int i=1;i<=N;i++) { cnt[suff[i]]++; len+=l[i]; for(int j=0;j<K;j++) { if((j*fac[len]+pref[i])%K) continue; ans+=dp[N&1][j]-cnt[j]; } } printf("%I64d\n",ans); } return 0; }
HDOJ 4669 Mutiples on a circle
标签:des style blog http io ar color os sp
原文地址:http://blog.csdn.net/ck_boss/article/details/41411359