您的位置:首页 > 其它

HDU 5555 (状压DP)

2018-01-29 21:28 316 查看

Immortality of Frog

[b]Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)

Total Submission(s): 373    Accepted Submission(s): 131
[/b]

[align=left]Problem Description[/align]
N frogs
are attempting to prolong their life-span. They live in the bottom of a well which can be described as a two-dimensional N×N grid. Grid(i,j) is
located in the i−th row
and the j−th column.
At the beginning, the i−th frog
lives in the bottom of i−th column,
i.e. the place below grid(1,i).

The frogs are so devout that God decides to give them a chance. In each row i,
a horizontal membrane ranging from (i,Li)
to (i,Ri) inclusively
is created. A capsule of elixir is placed at one of the grids of the membrane with uniform probability.

Now the frogs are jumping upwards to pursue immortality. The i−th frog
would be in grid(j,i) after j jumps.
When a frog arrives at a grid that contains a capsule of elixir, it will eat the capsule and gain immortality. After that, it continues jumping upwards until it gets out of the well.

A membrane is considered “bad” if it convers less than N grids.
The frogs are very sensitive, so they can only endure passing through 10 bad membrane. When a frog reaches the 11th bad
membrane, it thinks that there is no hope to get out of the well, so it will go back to the bottom of well and live there until death, even though it has eaten a capsule of elixir already.

The frogs are friends, so they want all of them gain immortality and live a happy life out of the well. They want to know the probability P that
every frog eats exactly one capsule of elixir and gets out of the well.

 

[align=left]Input[/align]
The first line of input contains a number T indicating
the number of test cases (T≤100).

Each test case starts with a line containing an integer N as
described above (1≤N≤1000).
The second line contains N space
separated integers L1,L2,...,LN.
The third line contains N space
separated integers R1,R2,...,RN.
(1≤Li≤Ri≤N)

 

[align=left]Output[/align]
For each test case, output a single line consisting of “Case #X: Y”. X is
the test case number starting from 1. Y is
an integer defined as the probability P multiplies ∏Ni=1(Ri−Li+1) .
As the answer could be huge, you only need to output it module 105225319.
 

[align=left]Sample Input[/align]

2
2
1 2
1 2
2
1 1
2 2

 

[align=left]Sample Output[/align]

Case #1: 1
Case #2: 2

 

[align=left]Source[/align]
2015ACM/ICPC亚洲区合肥站-重现赛(感谢中科大)
 

题意:
有一个N*N迷宫,每一行有一个横膜[L,R],每一个横膜上有一个长生药(位于横膜的某一个内(i,j)),现在有N只青蛙在井底(0,i)(1<=i<=n),青蛙只能沿着自己的列i向上跳去追求长生药,拿到长生药的青蛙就会继续向上跳出井,没拿到的就只能返回井底。并且横膜的长度为N的话称为好膜,<N的话称为坏膜,如果青蛙经过某一行是坏膜的话,心情就会变差。当踩上第11个坏膜时,青蛙会忍受到极限,即使有长生药的情况下,也会跳回井底。问有多少种药的放法,使得所有的青蛙都能跳出井

解析:
这里佷显然可以知道如果坏膜的数量>10个的话,所有青蛙都不可能逃生,ans=0
然后坏膜数<10的话,那么我们就可以用状压DP来做   这里可以先看一个博客点击打开链接

这里是对列进行dp,并且状压的对象是坏膜(因为坏膜的数量最多只有10个)
DP[i][j]第i列状态为j的方案数,j表示i列中存在的坏膜在1-i列的药的状态值
dp[i+1][j']是由第i+1列不放药的+第i+1列放药的得来,
反过来,就是dp[i][now](now为i列状态j变换成i+1列状态now)要为dp[i+1][now](不放药)和dp[i+1][(now|(1<<k))](在相对位置为k的坏膜放药)贡献答案

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long int lli;
#define MOD 105225319

const int MAXN = 1e3+100;
const int NN=(1<<10)+100;   //!

int LL[MAXN],RR[MAXN];
vector<int> g[MAXN];

int col1[20],col2[20];

lli dp[MAXN][NN];
int n;

void pre_treated(int x)
{
memset(col1,-1,sizeof(col1));
memset(col2,-1,sizeof(col2));
for(int i=0;i<g[x].size();i++)
{
for(int j=0;j<g[x+1].size();j++)
{
if(g[x][i]==g[x+1][j]) col1[i]=j;
}
}

for(int i=0;i<g[x+1].size();i++)
{
for(int j=0;j<g[x].size();j++)
{
if(g[x+1][i]==g[x][j]) col2[i]=j;
}
}
}

int _transform(int x,int y)   //将第i列的状态转换成i+1列的状态
{
int res=0;
for(int i=0;i<g[x].size();i++)
{
if(col1[i]==-1)
{
if((y&(1<<(i)))==0) return -1;  //非法情况,不加入计算
}
else
{
if((y&(1<<(i)))) res|=(1<<col1[i]);

}

}
return res;
}

int main()
{
int t;
int ncount=0;
int good;
scanf("%d",&t);
while(t--)
{
good=0;
ncount++;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&LL[i]);
}

for(int i=1;i<=n;i++)
{
scanf("%d",&RR[i]);
g[i].clear();
}
int maxcol=-1;
for(int i=1;i<=n;i++)   //预处理出每列坏膜的位置,用列来做DP
{
if(RR[i]-LL[i]+1==n)
{
good++;
continue;
}
maxcol=max(maxcol,i);
for(int j=LL[i];j<=RR[i];j++)
{
g[j].push_back(i);
}
}
int flag=0;
for(int i=1;i<=n;i++)
{
if(g[i].size()>10)
{
flag=1;
break;
}
}
printf("Case #%d: ",ncount);
if(flag)
{
printf("0\n");
}
else
{
memset(dp,0,sizeof(dp));
lli ans=0;
dp[0][0]=1;
for(int i=0;i<n;i++)  //第i列
{
pre_treated(i);
for(int j=0;j<(1<<(g[i].size()));j++)   //j=0的情况是表示第i列没有药的情况
{
int now=_transform(i,j);
if(now==-1) continue; //dp[i][j]中j是i列中存在的膜在1-i列的状态值,所以在1-i列可能存在非法的情况,但我们计算了,now==-1就是为了不让非法的情况
//加到后面的情况去
dp[i+1][now]=(dp[i+1][now]+dp[i][j])%MOD;   //表示i+1列没有药,将药都放在前面i列的情况加到对应的state里
//printf("dp[%d][%d]=%lld\n",i,j,dp[i][j]);
for(int k=0;k<g[i+1].size();k++)  //第x+1列的青蛙吃了相对位置为k的坏膜中的药(即k位置坏膜的药在第x+1列)
{
if(col2[k]==-1||(now&(1<<k))==0) //!(now>>k&1)保证了一行最多只有一个
{
dp[i+1][(now|(1<<k))]=(dp[i+1][(now|(1<<k))]+dp[i][j])%MOD;   //将第i列的状态转换成第i+1列的(now|(1<<k))
}
}
}
}
ans=dp
[((1<<g
.size())-1)]%MOD;//前面所有的情况(即使某些行在最后一列没有膜)都加入到最后一行上了,这样我们只要保证膜在最后一列的那些膜有药就行了
for(int i=good;i>1;i--)
{
ans=(ans*i)%MOD;
}
printf("%lld\n",ans);

}

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