0x5C 计数类DP
cf 559C 考虑到黑色的格子很少,那么我把(1,1)变成黑色,然后按每个黑色格子接近终点的程度排序,计算黑色格子不经过另一个黑色格子到达终点的方案,对于当前的格子,要减去在它右下角的所有方案数(注意不是f值)
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; const LL mod=1e9+7; LL MOD(LL x){return (x%mod+mod)%mod;} LL jc[310000],inv[310000]; LL quick_pow(LL A,LL p) { LL ret=1; while(p!=0) { if(p%2==1)ret=(ret*A)%mod; A=(A*A)%mod;p/=2; } return ret; } LL getC(int n,int m){return jc[m]*inv[m-n]%mod*inv[n]%mod;} struct node{int x,y;}a[2100]; bool cmp(node n1,node n2){return n1.x+n1.y>n2.x+n2.y;} LL f[2100]; int main() { jc[0]=1,inv[0]=1;for(int i=1;i<=300000;i++)jc[i]=(jc[i-1]*i)%mod,inv[i]=quick_pow(jc[i],mod-2); int n,m,K; scanf("%d%d%d",&n,&m,&K); for(int i=1;i<=K;i++) scanf("%d%d",&a[i].x,&a[i].y); a[++K].x=1,a[K].y=1; sort(a+1,a+K+1,cmp); for(int i=1;i<=K;i++) { f[i]=getC(n-a[i].x,(n+m)-(a[i].x+a[i].y)); for(int j=1;j<i;j++) if(a[i].x<=a[j].x&&a[i].y<=a[j].y) { f[i]=MOD( f[i]-MOD(f[j]*getC(a[j].x-a[i].x,(a[j].x+a[j].y)-(a[i].x+a[i].y))) ); } } printf("%I64d\n",f[K]); return 0; }
poj1737 口胡一波题解,我们知道n个点的无向图个数有2^(n*(n-1)/2)个,那么就去算不联通的,假设存在有一个包括点1的块大小为k,剩下的就是n-k个点的无向图个数了。
poj1037 其实可以借鉴一下康托展开的思想的。。。对于当前位应该选取最大的那个剩下位方案数少于m的,那么方案数就要用DP维护了。设f[i][j][k]表示枚举到第几位,选的是当前排第j的,是高位还是低位。
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; LL f[30][30][2]; void initf() { f[1][1][0]=f[1][1][1]=1; for(int i=2;i<=20;i++) for(int j=1;j<=i;j++) { for(int k=j;k<=i-1;k++)f[i][j][0]+=f[i-1][k][1]; for(int k=1;k<=j-1;k++)f[i][j][1]+=f[i-1][k][0]; } } bool v[30]; int main() { initf(); int T; scanf("%d",&T); while(T--) { int n;LL m; scanf("%d%lld",&n,&m); memset(v,false,sizeof(v)); int x,k; for(int j=1;j<=n;j++) { if(f[n][j][1]>=m){x=j,k=1;break;} else m-=f[n][j][1]; if(f[n][j][0]>=m){x=j,k=0;break;} else m-=f[n][j][0]; } v[x]=true;printf("%d",x); for(int i=2;i<=n;i++) { k^=1; int j=0; for(int y=1;y<=n;y++) { if(v[y]==true)continue; j++; if((k==0&&y<x)||(k==1&&y>x)) { if(f[n-i+1][j][k]>=m){x=y;break;} else m-=f[n-i+1][j][k]; } } v[x]=true;printf(" %d",x); } printf("\n"); } return 0; }
pain and happy in the cruel world.