Hdu-5519 Kykneion asma(状压DP+容斥)
来源:互联网 发布:西安电子大学网络教育 编辑:程序博客网 时间:2024/06/07 07:26
On the last day before the famous mathematician Swan's death, he left a problem to the world: Given integers n n and ai ai for 0≤i≤4 0≤i≤4, calculate the number of n n-digit integers which have at most ai ai-digit i i in its decimal representation (and have no 5,6,7,8 5,6,7,8 or 9 9). Leading zeros are not allowed in this problem.
105 0 1 2 3 45 1 1 1 1 15 2 2 2 2 25 3 3 3 3 35 3 2 1 3 25 3 2 0 0 05 0 0 0 5 07000 41 2467 6334 2500 31697000 7724 3478 5358 2962 4647000 5705 4145 7281 827 1961
Case #1: 535Case #2: 96Case #3: 1776Case #4: 2416Case #5: 1460Case #6: 4Case #7: 1Case #8: 459640029Case #9: 791187801Case #10: 526649529
题意: 给你包括0的5个数字,又告诉你每个数字的最多使用次数,问你由这5个数字组成的不同n位数(无前导0)有多少个。
分析:这题可以直接上母函数+FFT,但是不能直接用NTT因为模数不是费马素数,然后在网上看到了还有这种容斥+状压DP的做法,容斥很好想,但是难点在怎么用状压DP求给定数字集超出限制的方案数,这里有一个小trick就是如果我们想让某个数字i超出限制,那么直接放入a[i]+1个数字就行了,f[i][mask][j]表示当前在第i位,当前 mask 这些数字超出了限制,且最终超出限制的数字为j个的方案数,那么有:
f[i][mask][j] = f[i-1][mask][j]*(5 - j + count(mask))+sigma(f[i-a[k]-1][mask xor (1<<k)][j]*C(i-1,a[k]))
加上f[i-1][mask][j]这部分很容易理解,相当于枚举第i位的数字,右边的部分相当于在此刻刚好超过a[k]这个限制时的方案数。
#include <bits/stdc++.h>#define MOD 1000000007using namespace std;typedef long long ll;int T,Time,n,cnt[32],a[6];ll jc[15005],inv[15005],f[15005][32][6];void exgcd(ll a,ll b,ll &g,ll &x,ll &y){ if(!b) g=a,x=1,y=0; else { exgcd(b,a%b,g,y,x); y-=a/b*x; }}ll Inv(ll a,ll n){ ll d,x,y; exgcd(a,n,d,x,y); return d == 1 ? (x+n)%n : -1;}int lowbit(int x){ return x & -x;}ll c(int x,int y){ return (jc[x]*inv[y] % MOD)*inv[x-y] % MOD;}void add(ll &x,ll y){ y %= MOD; x = (x + y) % MOD;}ll got(int n){ memset(f,0,sizeof(f)); for(int i = 1;i <= 5;i++) f[0][0][i] = 1; for(int j = 1;j <= 5;j++) for(int i = 1;i <= n;i++) for(int mask = 0;mask < 32;mask++) if(cnt[mask] <= j) { add(f[i][mask][j],f[i-1][mask][j] * (5 - j + cnt[mask])); for(int k = 1;k <= 5;k++) if(((1<<(k-1)) & mask) && i >= a[k] + 1) add(f[i][mask][j],f[i - a[k] - 1][mask - (1<<(k-1))][j]*c(i-1,a[k])); } ll temp = 1; for(int i = 1;i <= n;i++) temp = temp*5 % MOD; for(int mask = 1;mask < 32;mask++) if(cnt[mask] & 1) temp = (temp - f[n][mask][cnt[mask]] + MOD) % MOD; else temp = (temp + f[n][mask][cnt[mask]]) % MOD; return temp;}int main(){ jc[0] = inv[0] = 1; for(int i = 1;i <= 15000;i++) jc[i] = jc[i-1] * i % MOD,inv[i] = Inv(jc[i],MOD); for(int i = 1;i < 32;i++) cnt[i] = cnt[i - lowbit(i)] + 1; cin.sync_with_stdio(false); cin>>T; while(T--) { cin>>n; for(int i = 1;i <= 5;i++) cin>>a[i]; if(!a[1]) cout<<"Case #"<<++Time<<": "<<got(n)<<endl; else { int temp = got(n); a[1]--; temp = (temp - got(n-1) + MOD) % MOD; cout<<"Case #"<<++Time<<": "<<temp<<endl; } }}
阅读全文
0 0
- Hdu-5519 Kykneion asma(状压DP+容斥)
- [DP 容斥原理] HDU 5519 Kykneion asma
- HDU 5519 Kykneion asma(沈阳站K题&&DP+容斥)
- HDU 5519(Kykneion asma-NNT+CRT)
- HDU 5838 Mountain(状压dp+容斥)
- HDU 5838 Mountain(状压DP+容斥)
- [HDU 5731]Solid Dominoes Tilings:状压DP+容斥原理
- 【多校】hdu 5731 Solid Dominoes Tilings 状压dp+容斥
- HDU5519 Kykneion asma (指数生成函数+快速数论变换模任意数+启发式合并思想)
- HDU5519 Kykneion asma (指数生成函数+快速数论变换模任意数+启发式合并思想)
- HDU - 5794 dp + 容斥思想 + Lucas
- HDU 6143 Killer Names(dp+容斥)
- hdu - 4336 - Card Collector - 容斥 || 概率dp
- HDU 4336 概率DP求期望(or容斥原理)
- hdu 4336 Card Collector (期望dp|容斥原理)
- HDU 4336 概率dp或者容斥原理
- hdu 4336 Card Collector(概率dp, 容斥原理)
- HDU 4632 Palindrome subsequence (区间dp 容斥定理)
- cartographer源码分析(41)-kalman_filter-gaussian_distribution.h
- hdu 2090 算菜价
- hdu 2091 空心三角形
- 剑指offer之面试题2:实现Singleton模式
- 《C和指针》全书"警告与编程提示"总结笔记
- Hdu-5519 Kykneion asma(状压DP+容斥)
- 层次聚类算法
- cartographer源码分析(43)-kalman_filterunscented_kalman_filter.h
- 浮动与清除浮动
- Hdu 5876 Sparse Graph bfs 变型最短路
- hdu 2092 整数解
- cartographer源码分析(44)-kalman_filter-pose_tracker.h
- hdu 2095 find your present (2)
- Linux系统调用