[FJOI2017]矩陣填數
阿新 • • 發佈:2019-03-25
problem mes ostream 轉移 log pro getc cpp main
[Luogu3813] [LOJ2280]
寫得很好的題解
\(1.\)離散化出每一塊內部不互相影響的塊
\(2.\)\(dp[i][j]\)為前 \(i\) 種重疊塊其中有 \(j\) 這些狀態的矩陣的最大值被滿足了的方案數 , 這樣轉移就之和這個塊有關了 , 直接計算取最大值和不取的方案數即可
則當取最大值時,把對應方案數轉移到 \(dp[i + 1][j | s[i + 1]]\),否則轉移到 \(dp[i + 1][j]\)
故 \(dp[Bcnt][(1 << n) - 1]\)為最終的方案
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define debug(...) fprintf(stderr,__VA_ARGS__) #define Debug(x) cout<<#x<<"="<<x<<endl #define y1 Y1 using namespace std; typedef long long LL; const int INF=1e9+7; inline LL read(){ register LL x=0,f=1;register char c=getchar(); while(c<48||c>57){if(c=='-')f=-1;c=getchar();} while(c>=48&&c<=57)x=(x<<3)+(x<<1)+(c&15),c=getchar(); return f*x; } const int N=10005; const int M=31; const int mod=1e9+7; int x1[M],x2[M],y1[M],y2[M],val[M]; int x[M],y[M],block[M*M],st[M*M],f[M*M][1100],blimit[M*M]; int n,m,Val,K,Xcnt,Ycnt,Bcnt; namespace Math{ inline int add(int x,int y){x+=y;return x>=mod?x-mod:x;} inline int dec(int x,int y){x-=y;return x<0?x+mod:x;} inline int mul(LL x,int y){x*=y;return x>=mod?x%mod:x;} inline int qpow(int a,int b){ int res=1; while(b){ if(b&1) res=mul(res,a); a=mul(a,a); b>>=1; } return res; } }using namespace Math; inline bool in(int x,int y,int i){ return x>=x1[i]&&x<=x2[i]&&y>=y1[i]&&y<=y2[i];//判斷(x,y)是否在i這個矩形裏面 } inline void init(){ memset(f,0,sizeof f); memset(st,0,sizeof st); x[Xcnt=0]=0; y[Ycnt=0]=0; Bcnt=0; } inline int solve(){ n=read(),m=read(),Val=read(),K=read(); x[++Xcnt]=0;//一定要記得放一個0!!! y[++Ycnt]=0; for(int i=1;i<=K;i++){ x1[i]=read(),y1[i]=read(),x2[i]=read(),y2[i]=read(),val[i]=read(); x[++Xcnt]=x1[i]-1; x[++Xcnt]=x2[i]; y[++Ycnt]=y1[i]-1; y[++Ycnt]=y2[i]; } x[++Xcnt]=n; y[++Ycnt]=m; sort(x+1,x+Xcnt+1); sort(y+1,y+Ycnt+1); Xcnt=unique(x+1,x+Xcnt+1)-x-1; Ycnt=unique(y+1,y+Ycnt+1)-y-1; for(int i=2;i<=Xcnt;i++) for(int j=2;j<=Ycnt;j++){ block[++Bcnt]=(x[i]-x[i-1])*(y[j]-y[j-1]); blimit[Bcnt]=Val; for(int k=1;k<=K;k++){ if(in(x[i],y[j],k)) blimit[Bcnt]=min(blimit[Bcnt],val[k]); } for(int k=1;k<=K;k++){ if(in(x[i],y[j],k)&&blimit[Bcnt]==val[k]) st[Bcnt]^=1<<(k-1); } } f[0][0]=1; for(int i=1;i<=Bcnt;i++){ //由於是這樣一塊一塊轉移,每次只需要考慮這一塊裏面的 int ful=st[i]; LL fail=qpow(blimit[i]-1,block[i]); LL success=dec(qpow(blimit[i],block[i]),fail);//這一塊取到最大值的方案 for(int j=0;j<(1<<K);j++){ f[i][j]=add(f[i][j],mul(f[i-1][j],fail)); f[i][j|ful]=add(f[i][j|ful],mul(f[i-1][j],success)); } } return f[Bcnt][(1<<K)-1]; } int main(){ for(int i=read();i;i--) init(),printf("%d\n",solve()); }
[FJOI2017]矩陣填數