想了最复杂的思路,用了最纠结的方法,花了最长的时间,蒙了一种规律然后莫名其妙的过了。
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
Problem Description
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.
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.
Input
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)
(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)
Output
For each test case, please output one line. The output format is "Case #x: ans", x is the case number, starting from 1.
Sample Input
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
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
Sample Output
Case #1: 28
Case #2: 76475
Case #2: 76475
Source
Recommend
#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[];//记录其中的小区域
}g[],tg[]; struct Rect
{
int x1,y1,x2,y2;
}rect[]; bool flag_noans;
int tmpsaverect[];
int tmprectcnt; long long savemul[];
bool saverectinarea[][];
bool flagrect[];
bool flagarea[];
bool flagg[];
int x[],y[];
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 ;
}
return ;
} int getrectareanum(int i)
{
return (rect[i].y2-rect[i].y1+)*(rect[i].x2-rect[i].x1+);
} long long quick_pow(int aa,int bb)//a^b
{
long long ans_pow=;
long long tmp_pow=aa;
while(bb)
{
if(bb&)
ans_pow = (ans_pow*tmp_pow)%MOD;
tmp_pow = (tmp_pow*tmp_pow)%MOD;
bb>>=;
}
return ans_pow;
} long long cnt_bigoneism(int allnum,int bigm)
{
return ((quick_pow(bigm,allnum)-quick_pow(bigm-,allnum))%MOD+MOD)%MOD;
} void dfs(int s,int ends,int cnt_nowhave,int tmp_m)
{
//明显错了
if(cnt_nowhave!=)
{
int cnt_inarea=;
int cnt_outarea=;
for(int i=;i<tmprectcnt;i++)
{
int tmp_flag=;
for(int j=;j<ends;j++)
{
if(flagarea[j]==true)
{
if( saverectinarea[i][j]==true )
{
tmp_flag=;
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==)
{
cnt_outarea += getrectareanum( tmpsaverect[i] );
} }
if( !(cnt_outarea==||cnt_inarea==) )
{
long long tmp_sum = ( quick_pow(tmp_m-,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+,ends,cnt_nowhave+,tmp_m);
flagarea[i]=false;
}
} long long get_numtime(int mxt,int tm)
{
//有t个不满足的情况
memset(flagarea,false,sizeof(flagarea));
ansans=;
dfs(,mxt,,tm);
return ansans;
} int main()
{
int T;
int tt=;
scanf("%d",&T);
//设计模式还是很成问题。
while(T--)
{
flag_noans=false;
scanf("%d%d%d%d",&h,&w,&m,&n);
for(int i=;i<n;i++)
{
int x1,y1,x2,y2,tmp;
scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&tmp);
x[*i]=x1;
x[*i+]=x2+;
y[*i]=y1;
y[*i+]=y2+; g[i].x1=x1;g[i].y1=y1;
g[i].x2=x2;g[i].y2=y2;
g[i].num=tmp;
g[i].areacnt=;
}
x[*n]=;
x[*n+]=h+;
y[*n]=;
y[*n+]=w+;
int id=;//用来标记最小矩形
sort(x,x+*(n+));
sort(y,y+*(n+));
int prex=;
for(int i=;i<*(n+);i++)
{
if(x[i]==prex) continue;
int prey=;
for(int j=;j<*(n+);j++)
{
if(y[j]==prey) continue;
rect[id].x1=prex;
rect[id].y1=prey;
rect[id].x2=x[i]-;
rect[id].y2=y[j]-;
prey=y[j];
id++;
}
prex=x[i];
} for(int i=;i<id;i++)
{
for(int j=;j<n;j++)
{
if( checkareabelong(i,j) == true )
{
g[j].area[ g[j].areacnt ]=i;
g[j].areacnt++;
}
}
} //然后就是容斥原理了 int cntother=;//统计有多少个格子是完全没有拘束的
for(int i=;i<id;i++)
{
bool signareain=;
for(int j=;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=;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=;//用来判断不满足条件的情况
memset(flagg,,sizeof(flagg));
ti--;
//[i,ti] have the same .num
tmprectcnt=;
int tmpcntnum=;
for(int j=;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]==)
{
flagg[gi]=;
cntcnt++;
}
}
}
} //容斥原理开始
if(tmprectcnt==||cntcnt!=ti-i+)
{
flag_noans=true;
break;
} for(int j=;j<tmprectcnt;j++)
for(int j1=;j1<ti-i+;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 = -;
long long num_mul=;
for(int j=;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 *= -;
//num_mul=(num_mul*(j+1))%MOD; }
get_numtime(ti-i+,g[i].num);
tmpans = tmpans + ansans;
ans = (ans*tmpans)%MOD;
i=ti;//这一步一直忘了
}
printf("Case #%d: ",tt++);
if(flag_noans==true)
cout<<<<endl;
else cout<<(ans%MOD+MOD)%MOD<<endl;
}
return ;
}