[容斥原理][dp]JZOJ P3056 數字
阿新 • • 發佈:2018-03-13
clas ++ 一個 set AR iostream 註意 ace 相等
題解
- 顯然我們可以問題為:
-
前n位之和與後n位之和相等的方案數+奇數位之和與偶數位之和相等的方案數-前n位之和與後n位之和相等且奇數位之和與偶數位之和相等的方案數
- 根據容斥原理可以將最後一個轉換為:
-
前n位奇數位之和=後n位偶數位之和 且 前n位偶數位之和=後n位奇數位之和
- 那麽前兩個都很容易求,跑一遍dp,f[i][j]表示i個數和為j的可能的方案數
- 那麽i個數可以為n個奇數,也可以為n個偶數
- 那麽前兩個的和就是∑(i=1,i<=n*9)2*f[n][i]*f[n][i] (ans)
- 定義兩個數l1=(n+1)/2,l2=n/2
- l1為前n個數的奇數個數和後n個數的偶數個數
- l2為前n個數的偶數個數和後n個數的奇數個數
- 知道這個後方案數自然很容易求
ans2=(ans2+f[l2][i]%mo*f[l2][i])%mo;ans1=(ans1+f[l1][i]%mo*f[l1][i])%mo;
- 答案為ans-ans1*ans2
- 註意要取膜
代碼
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 using namespace std; 5 const int mo=999983; 6 int n,len,a[15]; 7 long long ans1,ans2,sum,f[1005][1005*9]; 8 char s[15]; 9 int main() 10 { 11 scanf("%d",&n); 12 scanf("%s",s+1); 13 len=strlen(s+1); 14 for (int i=1;i<=len;i++) a[i]=s[i]-‘0‘; 15 f[0][0]=1; 16 for (int i=1;i<=n;i++) 17 for (int j=0;j<=i*9;j++) 18 for (int k=1;k<=len;k++) 19 if (j-a[k]>=0) 20 f[i][j]=(f[i][j]+f[i-1][j-a[k]])%mo; 21 for (int i=0;i<=n*9;i++) sum=(sum+2*f[n][i]%mo*f[n][i])%mo; 22 int l1=(n+1)/2,l2=n/2; 23 for (int i=0;i<=l1*9;i++) ans1=(ans1+f[l1][i]%mo*f[l1][i])%mo; 24 for (int i=0;i<=l2*9;i++) ans2=(ans2+f[l2][i]%mo*f[l2][i])%mo; 25 printf("%lld",(sum-ans1*ans2%mo+mo)%mo); 26 }
[容斥原理][dp]JZOJ P3056 數字