TopCoder SRM 568 Div1 500 EqualSums
阿新 • • 發佈:2018-12-12
這題可以說是花了一個多月才解決(霧
暑假的時候就很認真想過了,就是差了一步,昨天突然開竅。
emmm我真棒
我們發現題目的條件可以轉化為對於任意 有些是已知的,那麼我們就可以得到一些條件形如 但這樣還不夠,由於每個數都要,也就是說對任意, 就相當於要
於是我們就可以把所有和單獨拿出來,設為到,若就在之間連一條權值為的邊。對於一個聯通塊,只要其中一個點的權值確定了,整個聯通塊的點就都確定了。於是,我們就暴枚聯通塊中的一個點,把整個聯通塊求出來。再用,表示前個聯通塊,在已經求出的點中,且的方案數。滾動陣列優化掉一維,最後統計時只要保證就行了。
如果不知道的話,有兩種辦法。第一種是暴力列舉。第二種的話,我們可以發現交換任意兩行或任意兩列答案不變,就把一個知道的交換到就行了。
#include <bits/stdc++.h>
#define fr(i,x,y) for(int i=x;i<=y;i++)
using namespace std;
const int N=51;
const int M=N<<1;
const int p=1e9+7;
int n,a[N][N],x,m;
int g[M][M];
int c[M];
int b[M],vis[M];
int f[2][20][20];
template<class T> void checkmin(T &a,const T &b) { if (b<a) a=b; }
template<class T> void checkmax(T &a,const T &b) { if (b>a) a=b; }
class EqualSums {
public:
int count( vector <string> board ) ;
};
void Add(int &x,int y){
x+=y;
while(x>=p) x-=p;
}
void init(){
memset(c,-1,sizeof c);
fr(i,2,n) if (a[i][1]!=-1) c[i-1]=a[i][1];
fr(i,2,n) if (a[1][i]!=-1) c[i+n-2]=a[1][i];
}
void visit(int x){
b[x]=1;
for(int i=1;i<=m;i++)
if (g[x][i]!=-1&&!b[i]) visit(i);
}
int dfs(int x){
vis[x]=1;
if (c[x]<0) return 0;
for(int i=1;i<=m;i++){
if (g[x][i]==-1) continue;
if (vis[i]&&c[x]+c[i]!=g[x][i]) return 0;
if (vis[i]) continue;
if (c[i]!=-1&&c[x]+c[i]!=g[x][i]) return 0;
c[i]=g[x][i]-c[x];
if (!dfs(i)) return 0;
}
return 1;
}
int EqualSums::count(vector <string> board) {
n=board.size();
m=2*n-2;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if (board[i][j]=='-') a[i+1][j+1]=-1;
else a[i+1][j+1]=board[i][j]-'0';
int q=1,w=1;
fr(i,1,n) fr(j,1,n) if (a[i][j]!=-1){ q=i;w=j;break; }
//fr(i,1,n) swap(a[1][i],a[q][i]);
//fr(i,1,n) swap(a[i][1],a[i][w]);
int z,y;
if (a[1][1]==-1) z=0,y=18;
else z=a[1][1],y=a[1][1];
int ans=0;
for(x=z;x<=y;x++){
memset(g,-1,sizeof g);
memset(c,-1,sizeof c);
memset(f,0,sizeof f);
memset(b,0,sizeof b);
fr(i,2,n)
fr(j,2,n)
if (a[i][j]!=-1) g[i-1][j+n-2]=g[j+n-2][i-1]=a[i][j]+x;
//cout<<x<<endl;
//cout<<g[1][2]<<' '<<g[2][1];
init();
int cur=0;
f[0][19][19]=1;
//cout<<c[1]<<endl;
for(int i=1;i<=m;i++)
if (!b[i]){
init();
//cout<<c[1]<<endl;
//printf("i=%d,c[i]=%d\n",i,c[i]);
int zz,yy;
if (c[i]!=-1) zz=yy=c[i];
else zz=0,yy=18;
cur^=1;
memset(f[cur],0,sizeof f[cur]);
visit(i);
fr(j,zz,yy){
init();
c[i]=j;
memset(vis,0,sizeof vis);
if (!dfs(i)) continue;
//cout<<j<<endl;
int mn1=19,mn2=19;
for(int k=1;k<n;k++) if (c[k]>=0) mn1=min(mn1,c[k]);
for(int k=n;k<=m;k++) if (c[k]>=0) mn2=min(mn2,c[k]);
//printf("%d %d %d\n",j,mn1,mn2);
for(int k=0;k<=19;k++)
for(int l=0;l<=19;l++)
if (f[cur^1][k][l]) Add(f[cur][min(mn1,k)][min(mn2,l)],f[cur^1][k][l]);
}
}
fr(i,0,18)
fr(j,0,18)
if (i+j>=x) Add(ans,f[cur][i][j]);
}
return ans;
}