Kykneion asma
Time limit :1000ms
On the last day before the famous mathematician Swan's death, he left a problem to the world: Given integers n and ai for 0≤i≤4, calculate the number of n-digit integers which have at most ai-digit i in its decimal representation (and have no 5,6,7,8 or 9). Leading zeros are not allowed in this problem.
直接统计较为困难
考虑容斥:所有情况-至少一个超出+至少两个超出-.....
然后就可以状压dp了。dp[i][j]表示第i为状态为j,从低向高dp,每次可以把已经超出了的和不在意的任意填。或是枚举当前已超出的为在哪超出。乘组合数转移。
注意容斥思想的应用,直接统计较难时,先统计一部分,在减去重了的
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 #define maxn 20020 6 #define mod 1000000007 7 8 typedef long long LL; 9 LL dp[maxn][50]; 10 LL fac[maxn],inv[maxn],cnt[maxn]; 11 int ans; 12 int n,a[5]; 13 14 inline int power(LL x,int y){ 15 LL res = 1; 16 while ( y ){ 17 if ( y & 1 ) res = (res * x) % mod; 18 x = (x * x) % mod; 19 y >>= 1; 20 } 21 return res % mod; 22 } 23 void init(){ 24 fac[0] = 1; 25 for (int i = 1 ; i <= n ; i++){ 26 fac[i] = (fac[i - 1] * (LL) i) % mod;; 27 inv[i] = power(fac[i],mod - 2); 28 } 29 for (int i = 1 ; i < 32 ; i++){ 30 int now = i; 31 while ( now ) {if ( now & 1 ) cnt[i]++; now >>= 1;} 32 // cout<<cnt[i]<<" "; 33 } 34 //cout<<endl; 35 } 36 inline LL C(int n,int m){ 37 if ( n == m || m == 0 ) return 1; 38 if ( m > n ) return 0; 39 return (fac[n] * inv[m] % mod * inv[n - m] % mod) % mod; 40 } 41 int doDp(){ 42 int ans = power(5,n - 1); 43 for (int i = 1 ; i <= 5 ; i++){ //枚举状态中必须超出的数量 44 memset(dp,0,sizeof(dp)); 45 dp[0][0] = 1; 46 for (int j = 1 ; j <= n - 1 ; j++){ 47 for (int k = 0 ; k < 32 ; k++){ 48 if ( cnt[k] > i ) continue; 49 dp[j][k] = (dp[j][k] + (dp[j - 1][k] * (LL) (5 - i + cnt[k]))) % mod; 50 for (int l = 0 ; l <= 4 ; l++){ 51 if ( ((k >> l) & 1) && (j > a[l]) ) 52 dp[j][k] = (dp[j][k] + dp[j - a[l] - 1][(1 << l) ^ k] * C(j - 1,a[l])) % mod; 53 } 54 } 55 } 56 if ( i & 1 ){ 57 for (int j = 0 ; j < 32 ; j++) if ( i == cnt[j] ) ans = (int) ((LL)ans - dp[n - 1][j]) % mod; 58 } 59 else{ 60 for (int j = 0 ; j < 32 ; j++) if ( i == cnt[j] ) ans = (int) ((LL)ans + dp[n - 1][j]) % mod; 61 } 62 } 63 return (ans % mod + mod) % mod; 64 } 65 int main(){ 66 scanf("%d",&n); 67 for (int i = 0 ; i <= 4 ; i++) scanf("%d",&a[i]); 68 init(); 69 for (int i = 1 ; i <= 4 ; i++) if ( a[i] ) a[i]-- , ans = (ans + doDp()) % mod , a[i]++;//cout<<ans<<endl; 70 printf("%d ",ans); 71 return 0; 72 }