Immortality of Frog
Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 373 Accepted Submission(s): 131
Problem Description
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.
Input
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)
Output
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.
Sample Input
2 2 1 2 1 2 2 1 1 2 2
Sample Output
Case #1: 1 Case #2: 2
Source
题意:
有一个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的坏膜放药)贡献答案
关键就是第i列的状态转向第i+1列的状态时,我们对于同时覆盖i列和i+1列的坏膜的状态需要继承下去(其他的状态就不需要了),并且在第i列停止的坏膜我们需要保证他一定有一个药(合法)。然后我们就可以通过第i+1列的药在好膜上(即坏膜上不拿药)+第i+1列的药在坏膜上的情况。
#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[n][((1<<g[n].size())-1)]%MOD;//前面所有的情况(即使某些行在最后一列没有膜)都加入到最后一行上了,这样我们只要保证膜在最后一列的那些膜有药就行了
for(int i=good;i>1;i--)
{
ans=(ans*i)%MOD;
}
printf("%lld\n",ans);
}
}
return 0;
}