您的位置:首页 > 其它

更新一波题解(最近做的三个dp题)

2015-12-11 10:59 357 查看
很久没写题解了,去ec之前来填一填坑,希望能攒攒人品。。。

首先是去年上海F题。。uvalive7143

题意:

给n个人分 m间房子,每个房间的容量是已知的,其中有k对双胞胎,双胞胎可以看作相同的人,问总的方案数

其中n<=10W m=10 2k<=n

思路:

dp状态为, 前i个房子分完还剩多少对双胞胎(被拆散的不算)的方案数,转移结合组合数

代码:

#include <bits/stdc++.h>

using namespace std;

const long long mod=105225319;
struct node
{
int l, r;
};

vector<node> v;
vector<int> g[1010];
long long dp[1010][1<<11];
int l[1010];
int r[1010];
int getnum(int x,int t)
{
int res=-1;
for(int i=0; i<(int)g[t].size(); i++)
{
if(g[t][i]==x)
res=i;
}
return res;
}
int bz(int st,int now)
{
return ((st>>(now+1))<<(now+1)) + (st&((1<<now)-1));
}
long long f[1010];
int main()
{
f[0]=1;
for(int i=1; i<=1000; i++)
{
f[i]=f[i-1]*i%mod;
}
freopen("in.txt","r",stdin);
int T,cas=1;
scanf("%d",&T);
while(T--)
{
v.clear();
for(int i=1; i<=1000; i++)
{
g[i].clear();
}
int nn=0;
int n,x,y;
scanf("%d",&n);
for(int i=0; i<n; i++)
{
scanf("%d",l+i);
}
for(int i=0; i<n; i++)
{
scanf("%d",r+i);
}
for(int i=0; i<n; i++)
{
x=l[i],y=r[i];
if(y-x+1<n)
{
v.push_back(node{x,y});
}
else
{
nn++;
}
}
for(int i=0; i<(int)v.size(); i++)
{
for(int j=v[i].l; j<=v[i].r; j++)
{
g[j].push_back(i);
}
}
int ok=1;
for(int i=0; i<=n; i++)
{
if((int)g[i].size()>10)
{
ok=0;
}
}
if(!ok)
{
printf("Case #%d: 0\n",cas++);
continue;
}
memset(dp,0,sizeof(dp));
dp[0][0]=1;
for(int i=1; i<=n; i++)
{
for(int j=0; j<(1<<(int)g[i-1].size()); j++)
{
int st=(1<<(int)g[i].size())-1;
if(dp[i-1][j]==0)
continue;
ok=1;
for(int k=0; k<(int)g[i-1].size(); k++)
{
if(j&(1<<k))
{
if(v[g[i-1][k]].r<i)
{
ok=0;
}
}
else
{
if(v[g[i-1][k]].r>=i)
{
int now=getnum(g[i-1][k],i);
st=bz(st,now);
}
}
}
if(ok)
{
for(int k=0; k<(int)g[i].size(); k++)
{
if(st&(1<<k))
{
dp[i][bz(st,k)]+=dp[i-1][j];
dp[i][bz(st,k)]%=mod;
}
}
dp[i][st]+=dp[i-1][j];
dp[i][st]%=mod;
}
}
}
printf("Case #%d: %I64d\n",cas++,f[nn]*dp
[0]%mod);
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: