您的位置:首页 > 其它

hdu 5471(状压DP or 容斥)

2015-10-02 20:30 393 查看
想了最复杂的思路,用了最纠结的方法,花了最长的时间,蒙了一种规律然后莫名其妙的过了。

MD 我也太淼了。

后面想了下用状压好像还是挺好写的,而且复杂度也不高。推出的这个容斥的规律也没完全想透我就CAO。

Count the Grid

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 400 Accepted Submission(s): 86


[align=left]Problem Description[/align]
You get a grid of h rows and w columns. Rows are numbered 1, 2, 3, ... , h from top to bottom while columns are numbered 1, 2 , 3, ... , w from left to right. Each cell can be represented by a pair of numbers (x, y), which means this cell is located at row x column y.
You fill the every cell with an integer ranging from 1 to m.
Then you start to play with the gird. Every time you chose a rectangle whose upper left cell is (x1, y1) and lower right cell is (x2, y2), finally you calculate the maximum value v of this rectangle.
After you played n times, you left. When you return, you find that the grid is disappeared. You only remember n rectangles and their corresponding maximum value. You are wondering how many different gird can satisfy your memory. Two grids are different if there is a cell filled different integer.
Give your answer modulo (109+7).
Your memory may have some mistakes so that no grid satisfies it, in this case just output 0.

[align=left]Input[/align]
Multiple test cases. In the first line there is an integer T, indicating the number of test cases. For each test case. First line contain 4 integers h, w, m, n. Next are n lines, each line contain 5 integers x1, y1, x2, y2, v.
(T=55,1≤h,w,m≤104,1≤x1≤x2≤h,1≤y1≤y2≤w,1≤v≤m,1≤n≤10, there are i test cases for n = i)

[align=left]Output[/align]
For each test case, please output one line. The output format is "Case #x: ans", x is the case number, starting from 1.

[align=left]Sample Input[/align]

2
3 3 2 2
1 1 2 2 2
2 2 3 3 1
4 4 4 4
1 1 2 3 3
2 3 4 4 2
2 1 4 3 2
1 2 3 4 4

[align=left]Sample Output[/align]

Case #1: 28
Case #2: 76475

[align=left]Source[/align]
2015 ACM/ICPC Asia Regional Shanghai Online

[align=left]Recommend[/align]
hujie | We have carefully selected several similar problems for you: 5493 5492 5491 5490 5489

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <stdlib.h>
#include <math.h>
using namespace std;
#define MOD 1000000007

int h,w,m,n;
struct node
{
int x1,y1,x2,y2;
int num;
int areacnt;
int area[1010];//记录其中的小区域
}g[11],tg[11];

struct Rect
{
int x1,y1,x2,y2;
}rect[1010];

bool flag_noans;
int tmpsaverect[1010];
int tmprectcnt;

long long savemul[11];
bool saverectinarea[1010][11];
bool flagrect[1010];
bool flagarea[11];
bool flagg[11];
int x[22],y[22];
long long ans;
long long tmpans;
long long ansans;

bool cmpgnum(node tl,node tr)
{
return tl.num<tr.num;
}

bool checkareabelong(int rectpoint,int gi)
{
if(g[gi].x1<=rect[rectpoint].x1&&g[gi].y1<=rect[rectpoint].y1 && g[gi].x2>=rect[rectpoint].x2&&g[gi].y2>=rect[rectpoint].y2 )
{
return 1;
}
return 0;
}

int getrectareanum(int i)
{
return (rect[i].y2-rect[i].y1+1)*(rect[i].x2-rect[i].x1+1);
}

long long quick_pow(int aa,int bb)//a^b
{
long long ans_pow=1;
long long tmp_pow=aa;
while(bb)
{
if(bb&1)
ans_pow = (ans_pow*tmp_pow)%MOD;
tmp_pow = (tmp_pow*tmp_pow)%MOD;
bb>>=1;
}
return ans_pow;
}

long long cnt_bigoneism(int allnum,int bigm)
{
return ((quick_pow(bigm,allnum)-quick_pow(bigm-1,allnum))%MOD+MOD)%MOD;
}

void dfs(int s,int ends,int cnt_nowhave,int tmp_m)
{
//明显错了
if(cnt_nowhave!=0)
{
int cnt_inarea=0;
int cnt_outarea=0;
for(int i=0;i<tmprectcnt;i++)
{
int tmp_flag=0;
for(int j=0;j<ends;j++)
{
if(flagarea[j]==true)
{
if( saverectinarea[i][j]==true )
{
tmp_flag=1;
cnt_inarea += getrectareanum( tmpsaverect[i] );
break;
}

/*
if( tg[j].x1<=rect[tmpsaverect[i]].x1&&tg[j].y1<=rect[tmpsaverect[i]].y1&& tg[j].x2>=rect[tmpsaverect[i]].x2&&tg[j].y2>=rect[tmpsaverect[i]].y2 )
{
tmp_flag=1;
cnt_inarea += getrectareanum( tmpsaverect[i] );
break;
}
*/
}
}
if(tmp_flag==0)
{
cnt_outarea += getrectareanum( tmpsaverect[i] );
}

}
if( !(cnt_outarea==0||cnt_inarea==0) )
{
long long tmp_sum = ( quick_pow(tmp_m-1,cnt_inarea)*cnt_bigoneism(cnt_outarea,tmp_m) )%MOD;
ansans = (ansans+savemul[cnt_nowhave]*tmp_sum)%MOD;
}
}
for(int i=s;i<ends;i++)
{
flagarea[i]=true;
dfs(i+1,ends,cnt_nowhave+1,tmp_m);
flagarea[i]=false;
}
}

long long get_numtime(int mxt,int tm)
{
//有t个不满足的情况
memset(flagarea,false,sizeof(flagarea));
ansans=0;
dfs(0,mxt,0,tm);
return ansans;
}

int main()
{
int T;
int tt=1;
scanf("%d",&T);
//设计模式还是很成问题。
while(T--)
{
flag_noans=false;
scanf("%d%d%d%d",&h,&w,&m,&n);
for(int i=0;i<n;i++)
{
int x1,y1,x2,y2,tmp;
scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&tmp);
x[2*i]=x1;
x[2*i+1]=x2+1;
y[2*i]=y1;
y[2*i+1]=y2+1;

g[i].x1=x1;g[i].y1=y1;
g[i].x2=x2;g[i].y2=y2;
g[i].num=tmp;
g[i].areacnt=0;
}
x[2*n]=1;
x[2*n+1]=h+1;
y[2*n]=1;
y[2*n+1]=w+1;
int id=0;//用来标记最小矩形
sort(x,x+2*(n+1));
sort(y,y+2*(n+1));
int prex=1;
for(int i=0;i<2*(n+1);i++)
{
if(x[i]==prex) continue;
int prey=1;
for(int j=0;j<2*(n+1);j++)
{
if(y[j]==prey) continue;
rect[id].x1=prex;
rect[id].y1=prey;
rect[id].x2=x[i]-1;
rect[id].y2=y[j]-1;
prey=y[j];
id++;
}
prex=x[i];
}

for(int i=0;i<id;i++)
{
for(int j=0;j<n;j++)
{
if( checkareabelong(i,j) == true )
{
g[j].area[ g[j].areacnt ]=i;
g[j].areacnt++;
}
}
}

//然后就是容斥原理了

int cntother=0;//统计有多少个格子是完全没有拘束的
for(int i=0;i<id;i++)
{
bool signareain=0;
for(int j=0;j<n;j++)
{
if( checkareabelong(i,j)==true )
{
signareain=true;
break;
}
}
if(signareain == false)
{
cntother += getrectareanum(i);
}
}
ans=quick_pow(m,cntother);
sort(g,g+n,cmpgnum);
memset(flagrect,false,sizeof(flagrect));
for(int i=0;i<n;i++)
{
int ti;
for(ti=i;ti<n;ti++)
{
if( g[ti].num != g[i].num ) break;
tg[ti-i]=g[ti];
}
int cntcnt=0;//用来判断不满足条件的情况
memset(flagg,0,sizeof(flagg));
ti--;
//[i,ti] have the same .num
tmprectcnt=0;
int tmpcntnum=0;
for(int j=0;j<id;j++)
{
if( flagrect[j]==true ) continue;//已经计数过的,不需要
for(int gi=i;gi<=ti;gi++)
if( checkareabelong(j,gi)==true )
{
flagrect[j]=true;
tmpsaverect[tmprectcnt]=j;
tmpcntnum += getrectareanum(j);
tmprectcnt++;
break;
}
for(int gi=i;gi<=ti;gi++)
{
if( checkareabelong(j,gi)==true )
{
if(flagg[gi]==0)
{
flagg[gi]=1;
cntcnt++;
}
}
}
}

//容斥原理开始
if(tmprectcnt==0||cntcnt!=ti-i+1)
{
flag_noans=true;
break;
}

for(int j=0;j<tmprectcnt;j++)
for(int j1=0;j1<ti-i+1;j1++)
{
if( tg[j1].x1<=rect[tmpsaverect[j]].x1&&tg[j1].y1<=rect[tmpsaverect[j]].y1&& tg[j1].x2>=rect[tmpsaverect[j]].x2&&tg[j1].y2>=rect[tmpsaverect[j]].y2 )
{
saverectinarea[j][j1]=true;
}
else saverectinarea[j][j1]=false;
}

tmpans = cnt_bigoneism(tmpcntnum,g[i].num);// 总的个数
int flag_sign = -1;
long long num_mul=1;
for(int j=1;j<=ti-i;j++)
{
savemul[j]=flag_sign*num_mul;
//tmpans = tmpans + flag_sign*num_mul*get_numtime(j,ti-i+1,g[i].num);//j个不满足的情况
//tmpans = (tmpans%MOD+MOD)%MOD;
flag_sign *= -1;
//num_mul=(num_mul*(j+1))%MOD;

}
get_numtime(ti-i+1,g[i].num);
tmpans = tmpans + ansans;
ans = (ans*tmpans)%MOD;
i=ti;//这一步一直忘了
}
printf("Case #%d: ",tt++);
if(flag_noans==true)
cout<<0<<endl;
else cout<<(ans%MOD+MOD)%MOD<<endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: