[XXII Open Cup. Grand Prix of Korea]
XXII Open Cup. Grand Prix of Korea
A Automatic Sprayer 2
简要题意
定义两点间的距离为曼哈顿距离,每个点的点值非负,以这个点值向外扩散。给出最终的权值和,反推每个点的点值。\(E\)为求和后的矩阵,\(A\)为点值矩阵,即
\[E_{i,j} = \sum_{x,y} A_{x,y} (|x-i|+|y-j|)
\]
题解
观察矩阵\(E\)发现相邻两行,两列之间的差值是定值,考虑两列元素的差值的意义。当前在第\(i\)列,向右移动一个单位,\(E\)的改变量是前\(i\)列的\(A\)之和减去后\(n-i\)列的和。这样的话我们可以得到第\(i\)列的和。
\(C_i = \sum_{j=1}^n A_{j,i}\)表示第\(i\)列的和,\(Sc_{i,j}\)表示第\(i\)列到第\(j\)列的和。
\[E_{1,i+1} = E_{1,i} + Sc_{1,i-1} + C_i - Sc_{i+1,n} \\
E_{1,i} = E_{1,i-1} + Sc_{1,i-1} - C_i - Sc_{i+1,n} \\
2C_i = E_{1,i+1} + E_{1,i-1} - 2E_{1,i} \\
C_i = \frac{E_{1,i+1} + E_{1,i-1} - 2E_{1,i}} {2}
\]
同理我们可以得到行和。
特别的,第一行,第\(n\)行,第一列,第\(n\)列要特殊处理
\[R_1 + C_1 = \frac{\bigg(E_{n,n} - \sum_{x=2}^{n-1} (|x-n|R_x) - \sum_{y=2}^{n-1}(|y-n|C_y) \bigg)} {n-1} \\
R_1 + C_n = \frac{\bigg(E_{n,n} - \sum_{x=2}^{n-1} (|x-n|R_x) - \sum_{y=2}^{n-1}(|y-1|C_y) \bigg)} {n-1} \\
R_n + C_1 = \frac{\bigg(E_{n,n} - \sum_{x=2}^{n-1} (|x-1|R_x) - \sum_{y=2}^{n-1}(|y-n|C_y) \bigg)} {n-1} \\
R_1 + R_n + \sum_{x=2}^{n-1} R_x = C_1 + C_n + \sum_{y=2}^{n-1} C_y
\]
至此我们得到了每一行每一列的和,我们考虑如何求出一组满足条件的解。一个小技巧就是令
for i \leftarrow 1 to n
for j \leftarrow 1 to n
A_{i,j} \leftarrow min(R_i,C_j)
R_i \leftarrow R_i - A_{i,j}
C_j \leftarrow C_j - A_{i,j}
这样就能找到一组合法解。
#include <bits/stdc++.h>
#define LL long long
#define pb push_back
#define mp make_pair
#define pii pair<int,int>
#define fi first
#define se second
#define lc nd<<1
#define rc nd<<1|1
#define lowbit(x) (x&(-x))
#define pLL pair<LL,LL>
using namespace std;
const int mn=1006;
LL e[mn][mn],r[mn],c[mn],ans[mn][mn];
int n;
int main()
{
int tests=1;//scanf("%d",&tests);
while(tests--) {
scanf("%d",&n);
for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) scanf("%lld",&e[i][j]);
for(int i=2;i<n;++i) c[i]=(e[1][i-1]+e[1][i+1]-2*e[1][i])/2;
for(int i=2;i<n;++i) r[i]=(e[i-1][1]+e[i+1][1]-2*e[i][1])/2;
LL s1=e[n][n];
for(int i=2;i<n;++i) s1-=r[i]*abs(i-n)+c[i]*abs(i-n);
s1/=(n-1);
LL s2=e[n][1];
for(int i=2;i<n;++i) s2-=r[i]*abs(i-n)+c[i]*abs(i-1);
s2/=(n-1);
LL s3=e[1][n];
for(int i=2;i<n;++i) s3-=r[i]*abs(i-1)+c[i]*abs(i-n);
s3/=(n-1);
LL s4=0;
for(int i=2;i<n;++i) s4+=c[i]-r[i];
r[1]=(s1+s2+s4+s1-s3)/4;
r[n]=r[1]+s3-s1;
c[1]=s1-r[1];
c[n]=s2-r[1];
for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) {
ans[i][j]=min(r[i],c[j]);
r[i]-=ans[i][j],c[j]-=ans[i][j];
}
for(int i=1;i<=n;++i) {
for(int j=1;j<=n;++j) printf("%lld ",ans[i][j]);
puts("");
}
}
return 0;
}
C Equivalent Pipelines
简要题意
树上两点\(u,v\)间路径\(\{a\}\)满足\(a_0=u,a_d=v\),\(a_i\)与\(a_{i-1}\)之间有边相连,距离定义为\(\min{w_{a_i,a_{i-1}}}\)。
定义两棵树同构当且仅当
\[\forall i,j, \ d_a(i,j) = d_b(i,j)
\]
给出\(d\)棵树,对第\(i\)棵树,输出和它同构的树的最小的编号。
题解
考虑通过建树过程判断同构。对边权从大到小排序,这样每加入一条边,会把两个子树合并起来,并且对于左右端点分别在两个子树内的\(d(i,j)\),它们的答案一定是当前边的边权。这样可以通过并查集和map记录所有信息。
判断记录下的信息相同时可以用哈希。
\[hash = \sum f_a*f_b*d(a,b)
\]
哈希时一个小trick是给每个点随机权值,而不是用\(p^i\)表示\(i\)的权值。
#include <bits/stdc++.h>
#define LL long long
#define pb push_back
#define mp make_pair
#define pii pair<int,int>
#define fi first
#define se second
#define lc nd<<1
#define rc nd<<1|1
#define lowbit(x) (x&(-x))
#define pLL pair<LL,LL>
using namespace std;
const int mn=5e5+6,p=935935,mod1=1e9+7,mod2=998244353;
int d,n,fa[mn];
LL po1[mn],po2[mn],siz1[mn],siz2[mn];
map<LL,int> ans;
LL qpow(LL a,LL b,LL mod)
{
LL ans=1;a%=mod;
while(b) {
if(b&1) ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
struct edge {
int u,v,w;
};
vector<edge> e;
bool cmp(edge a,edge b) {return a.w>b.w;}
vector<pair<pLL,LL>> vec1,vec2;
int find(int x) {if(fa[x]==x) return x;return fa[x]=find(fa[x]);}
void init()
{
srand(998244353);
for(int i=1;i<mn;++i) po1[i]=1ll*rand()*rand()%mod1,po2[i]=1ll*rand()*rand()%mod2;
}
int main()
{
// freopen("t.in","r",stdin);
init();
scanf("%d%d",&d,&n);
for(int _=1;_<=d;++_) {
e.clear();vec1.clear();vec2.clear();
int u,v,w;
for(int i=1;i<=n;++i) fa[i]=i,siz1[i]=po1[i],siz2[i]=po2[i];
for(int i=1;i<n;++i) {
scanf("%d%d%d",&u,&v,&w);
e.pb(edge{u,v,w});
}
sort(e.begin(),e.end(),cmp);
for(int i=0;i<n-1;++i) {
int x=find(e[i].u),y=find(e[i].v);
if(x==y) continue;
fa[x]=y;
vec1.pb(mp(mp(siz1[x],siz1[y]),e[i].w));
vec2.pb(mp(mp(siz2[x],siz2[y]),e[i].w));
siz1[y]=(siz1[y]+siz1[x])%mod1;
siz2[y]=(siz2[y]+siz2[x])%mod2;
}
LL s1=0,s2=0,val1,val2;
for(int i=0;i<vec1.size();++i) {
val1=vec1[i].fi.fi*vec1[i].fi.se%mod1;
val2=vec2[i].fi.fi*vec2[i].fi.se%mod2;
s1+=val1*vec1[i].se%mod1;
s2+=val2*vec1[i].se%mod2;
}
s1%=mod1,s2%=mod2;
if(ans.find(s1*mod2+s2*mod1)==ans.end()) {
ans[s1*mod2+s2*mod1]=_;
}
printf("%d ",ans[s1*mod2+s2*mod1]);
}
return 0;
}

浙公网安备 33010602011771号