bzoj5470 / P4578 [FJOI2018]所罗门王的宝藏

P4578 [FJOI2018]所罗门王的宝藏

设第$i$行上的值改变了$r1[i]$,第$j$列上的值改变了$r2[i]$

显然密码$(i,j,c)=r1[i]+r2[j]$

对于同一列上的两个密码$(i_{1},j,c_{1}),(i_{2},j,c_{2})$,它们的差值即为$c_{1}-c_{2}=r1[i_{1}]-r1[i_{2}]$

同一行上的同理。

这样我们就可以确定$r1[i],r2[j]$之间的关系,并以此判断

那么对于每组数据,我们可以$O(k^2)$两两枚举宝石,用上述方法判断即可。

同一个地方可能有两颗宝石

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cctype>
 5 using namespace std;
 6 void read(int &x){
 7     char c=getchar();x=0;bool f=1;
 8     while(!isdigit(c)) f=(f&&c!='-'),c=getchar();
 9     while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
10     x=f?x:-x;
11 }
12 #define N 1005
13 int n,m,k,x[N],y[N],v[N],d1[N][N],d2[N][N];
14 bool w1[N][N],w2[N][N],ok;
15 int ask(int i,int j,int c){
16     if(c) return y[i]<y[j]?v[i]-v[j]:v[j]-v[i];
17     else  return x[i]<x[j]?v[i]-v[j]:v[j]-v[i];
18 }
19 bool check(int i,int j){
20     if(x[i]==x[j]&&y[i]==y[j]&&v[i]!=v[j]) return 0;//同个位置两颗宝石
21     if(y[i]==y[j]){
22         if(w1[x[i]][x[j]]&&d1[x[i]][x[j]]!=ask(i,j,0)) return 0;
23         d1[x[i]][x[j]]=d1[x[j]][x[i]]=ask(i,j,0);
24         w1[x[i]][x[j]]=w1[x[j]][x[i]]=1;
25     }
26     if(x[i]==x[j]){
27         if(w2[y[i]][y[j]]&&d2[y[i]][y[j]]!=ask(i,j,1)) return 0;
28         d2[y[i]][y[j]]=d2[y[j]][y[i]]=ask(i,j,1);
29         w2[y[i]][y[j]]=w2[y[j]][y[i]]=1;
30     }return 1;
31 }
32 int main(){
33     int T;read(T);
34     while(T--){
35         memset(d1,0,sizeof(d1));
36         memset(d2,0,sizeof(d2));
37         memset(w1,0,sizeof(w1));
38         memset(w2,0,sizeof(w2));
39         read(n);read(m);read(k);ok=1;
40         for(int i=1;i<=k;++i)
41             read(x[i]),read(y[i]),read(v[i]);
42         for(int i=1;i<=k&&ok;++i)
43             for(int j=i+1;j<=k&&ok;++j)
44                 ok=check(i,j);
45         printf(ok?"Yes\n":"No\n");
46     }return 0;
47 }
View Code

(神仙做法,学不来学不来)

猜你喜欢

转载自www.cnblogs.com/kafuuchino/p/10082585.html