AtCoder Regular Contest 107
Contest Link
Official Editorial
比赛体验良好,网站全程没有挂。题面简洁好评,题目质量好评。对于我这个蒟蒻来说非常合适的一套题目。
A. Simple Math
Description
Given are three positive integers \(A,B,\) and \(C\) . Compute the following value modulo \(998244353:\sum_{a=1}^A\sum_{b=1}^B\sum_{c=1}^C a\times b\times c.\)
\(1\leq A,B,C\leq 1e9\)
Solution
疯狂取模就好了。
Code
赛时用时 5min。
//Author: RingweEH
const ll mod=998244353;
int main()
{
ll A=read(),B=read(),C=read();
A%=mod; B%=mod; C%=mod;
A=A*(A+1)/2%mod; B=B*(B+1)/2%mod; C=(C*(C+1))/2%mod;
ll ans=A*B%mod*C%mod;
printf( "%lld",ans );
}
B. Quadruple
Description
Given are integers \(N\) and \(K\) . How many quadruples of integers \((a,b,c,d)\) satisfy both of the following conditions?
- \(1\leq a,b,c,d\leq N\)
- \(a+b-c-d=K\)
\(1\leq N\leq 1e5,-2(N-1)\leq K\leq 2(N-1)\)
Solution
暴力枚举显然非常的不可行。按照正负,把原来的式子分成两部分:
- \(a+b=x\)
- \(c+d=x-K\)
然后对于每一部分,设 \(f(N,K)\) 表示 \(1\leq a,b\leq N\) 时 \(a+b=K\) 的方案数。于是得到:
然后 \(O(N)\) 算一下就好了。不过容斥可以做到 \(O(1)\) 。
注意特判 \(f(N,K)\) 中 \(K\) 不合法的情况。
Code
赛时用时 40min.
//Author:RingweEH
ll n,k;
ll calc( ll n,ll k )
{
if ( k<2 ) return 0;
if ( k>2*n ) return 0;
return min( k-1,2*n+1-k );
}
int main()
{
n=read(); k=read();
ll ans=0;
for ( int i=2; i<=2*n; i++ )
ans=ans+calc( n,i )*calc( n,i-k );
printf( "%lld",ans );
}
C. Shuffle Permutation
Description
Given are an \(N\times N\) matrix and an integer \(K\). The entry in the \(i\)-th row and \(j\)-th column of this matrix is denoted as \(a_{i,j}\) . This matrix contains each of \(1,2,...,N^2\) exactly once.
Sigma can repeat the following two kinds of operation arbitrarily many times in any order.
- Pick two integers \(x,y(1\leq x<y\leq N)\) that satisfy \(a_{i,x}+a_{i,y}\leq K\) for all \(i(1\leq i\leq N)\) and swap the \(x\)-th and the \(y\)-th columns.
- Pick two integers \(x,y(1\leq x<y\leq N)\) that satisfy \(a_{x,i}+a_{y,i}\leq K\) for all \(i(1\leq i\leq N)\) and swap the \(x\)-th and the \(y\)-th rows.
How many matrices can he obtain by these operations?Find it modulo \(998244353.\)
\(1\leq N\leq 50. 1\leq K\leq 2\times N^2.\)
Solution
啥都不知道,开始手模样例。
3min之后……发现自己是个思博。显然行列之间没什么关系。所以乘起来就好了。
然后呢?还是不知道行列怎么算。
仔细思考时候发现,如果把行(或者列)当成点,能够 swap
就连边,会发现凡是联通块内点都能任意互换。
A-B-C => B-A-C => B-C-A => C-B-A
以上是列的 \(N=3\) 情况。那么只需要暴力枚举判断加边,带权并查集就好了(事实上直接统计也行)。
Code
赛时用时 40min.
WA 了一发,原因是把计算行/列的情况中乘法原理搞成了加法……就这还能 AC \(\dfrac{22}{25}\) ……没话讲。
//Author:RingweEH
//由于代码具有强对称性,删减了部分 copy 的函数使得代码看上去更加简短(
int find_r( int x )
{
return x==fa_r[x] ? x : fa_r[x]=find_r( fa_r[x] );
}
void merge_r( int x,int y )
{
int fx=find_r(x),fy=find_r(y);
if ( fx==fy ) return;
fa_r[fx]=fy;
}
void init()
{
fac[0]=1;
for ( int i=1; i<=50; i++ )
fac[i]=fac[i-1]*i%mod;
}
int main()
{
for ( int i=1; i<=n; i++ )
fa_c[i]=i,fa_r[i]=i;
for ( int i=1; i<=n; i++ )
for ( int j=i+1; j<=n; j++ )
{
bool fl=1;
for ( int k=1; k<=n; k++ )
if ( a[k][i]+a[k][j]>K ) fl=0;
if ( fl ) merge_r( i,j );
}
memset( cntr,0,sizeof(cntr) ); memset( cntc,0,sizeof(cntc) );
for ( int i=1; i<=n; i++ )
cntr[find_r(i)]++,cntc[find_c(i)]++;
ll ans1=1,ans2=1; init();
for ( int i=1; i<=n; i++ )
{
if ( cntr[i]>1 ) ans1=(ans1*fac[cntr[i]])%mod;
if ( cntc[i]>1 ) ans2=(ans2*fac[cntc[i]])%mod;
}
printf( "%lld\n",ans1*ans2%mod );
}
D.Number of Multisets
Description
You are given two positive integers \(N\) and \(K\) . How many multisets of raional numbers satisfy all of the following conditions?
- The multiset has exactly \(N\) elements and the sum of them is equal to \(K\).
- Each element of the multiset is one of \(1,\dfrac{1}{2},\dfrac{1}{4},...\) . In other words,each element can be represented as \(\dfrac{1}{2^i}(i=0,1,...)\)
The answer may be large,so print it modulo \(998244353.\)
Solution
小清新分讨DP题。
分为两类:用 \(1\) 的和不用的。
对于用了至少一个 \(1\) 的,\(f[i][j]=f[i-1][j-1]\)
对于没有用 \(1\) 的,\(f[i][j]=f[i][2\times j]\)
显然把所有元素乘2就是等价的了。
综上, \(f[i][j]=f[i-1][j-1]+f[i][2\times j]\).
最后考虑边界就好了: \(f[i][j]=0(i<j)\)
时间复杂度 \(O(N^2)\)
Code
//Author: RingweEH
int main()
{
n=read(); k=read();
f[0][0]=1;
for ( int i=1; i<=n; i++ )
for ( int j=i; j; j-- )
f[i][j]=(f[i-1][j-1]+(j*2>i ? 0 : f[i][j*2]) )%mod;
printf( "%lld",f[n][k] );
}
E. Mex Mat
Description
Consideer an \(N\times N\) matrix, Let us denote by \(a_{i,j}\) the entry in the \(i\)-th row and \(j\)-th column. For \(a_{i,j}\) where \(i=1\) or \(j=1\) holds,its value is one of \(0,1,2\) and given in the input. The remaining entries are defined as follows:
- \(a_{i,j}=mex(a_{i-1,j},a_{i,j-1})(2\leq i,j\leq N)\)
( \(mex\) 定义见题面)
How many entries of the matrix are \(0,1,2\) respectively ?
Solution
一开始看成了SG函数的那个 mex
emmm
神仙结论题……官方题解简洁而优雅 暴力 。
官方题解给了一个 \(20\times 20\) 的随机矩阵的完整形式,然后发现在 \(i>4,j>4\) 之后都有 \(a_{i,j}=a_{i-1,j-1}\) ,暴力跑前面的四行四列即可。
证明……你可以暴力跑 \(n=5\) 的矩阵,然后有 \(a_{4,4}=a_{5,5}\) ,按这个性质下去就好了。
Code
REH 这个zz又写错了一次边界……
//Author: RingweEH
for ( int i=2; i<=10; i++ )
{
a[i-1]=b[i];
for ( int j=i; j<=n; j++ )
cnt[a[j]=mex[a[j]][a[j-1]]]++;
b[i]=a[i];
for ( int j=i+1; j<=n; j++ )
cnt[b[j]=mex[b[j]][b[j-1]]]++;
}
F. Sum of Abs
Description
Given is a simple undirected graph with \(N\) vertices and \(M\) edges. Its vertices are numbered \(1,2,...,N\) and its edges are numbered \(1,2,..,M\) .On Vertex \(i(1\leq i\leq N)\) two integers \(A_i\) and \(B_i\) are written. Edge \(i(1\leq i\leq M)\) connects Vertices \(U_i\) and \(V_i\) .
Snuke picks zero or more vertices and delete them. Deleting Vertex \(i\) costs \(A_i\) . When a vertex is deleted,edges that are incident to the vertex are also deleted. The score after deleting vertices is calculated as follows:
- The score is the sum of the scores of all connected components.
- The score of a connected component is the absolute value of the sum of \(B_i\) of the vertices in the connected component.
Find the maxinum possible profit Snuke can gain. profit is (score)-(the sum of costs).
Solution
很好的网络流建模练习题。
简化题意:\(n\) 点 \(m\) 边的无向图,删点代价 \(A_i\) ,最大化所有连通块 \(B_i\) 之和的绝对值之和减去总代价。
价值就等价于给每个点一个系数 \(p_i=\pm 1\) ,使得 \(\forall (x,y)\in E,p_x=p_y\) 的最大的 \(\sum_{i=1}^n p_ib_i\)
考虑网络流建图:将 \(b_i\) 分为正负两类, \(S\) 向正的连 \(2b_i\) 的边,负的向 \(T\) 连 \(-2b_i\) 的边,图中直接相连的两点连上 \(\infty\) (如果两点不同向,必须有一个被割掉)
再来看删除操作。可以看做这个点不要求正负,且不帮助连边。那么进行拆点,建立一条 \((i,i+n)\in E'\) ,流量为 \(a_i+|b_i|\) 表示删除的代价。
对于一条原图中的边,连 \((x+n,y),(y+n,x)\) ,此时若 \((x,x+n)\) 被删掉,那么 \(x\) 就到不了 \(y+n\) .
最终答案就是 \(\sum_{i=1}^n |b_i|\) 减去最小割。
Code
//Author: RingweEH
void add( int u,int v,int w )
{
e[tot].to=v; e[tot].nxt=head[u]; head[u]=tot; e[tot].val=w; tot++;
if ( tot&1 ) add( v,u,0 );
}
bool bfs()
{
memset( dis,inf,sizeof(dis) ); dis[0]=0; q.push( 0 );
while ( !q.empty() )
{
int u=q.front(); q.pop();
for ( int i=head[u]; i!=-1; i=e[i].nxt )
{
int v=e[i].to;
if ( !e[i].val || (dis[v]!=inf) ) continue;
dis[v]=dis[u]+1; q.push( v );
}
}
return dis[2*n+1]!=inf;
}
int dfs( int u,int res )
{
if ( u>2*n ) return res;
for ( int i=head[u]; i!=-1; i=e[i].nxt )
{
int v=e[i].to;
if ( !e[i].val || (dis[v]!=dis[u]+1) ) continue;
int tmp=dfs( v,min(res,e[i].val) );
if ( tmp ) { e[i].val-=tmp,e[i^1].val+=tmp; return tmp; }
}
return 0;
}
int Dinic()
{
int num,res=0;
while ( bfs() )
while ( num=dfs( 0,inf ) ) res+=num;
return res;
}
int main()
{
n=read(); m=read();
for ( int i=1; i<=n; i++ )
a[i]=read();
memset( head,-1,sizeof(head) ); int ans=0;
for ( int i=1,x; i<=n; i++ )
{
x=read(); ans+=abs(x);
add( i,i+n,abs(x)+a[i] );
if ( x>=0 ) add( 0,i,2*x );
else add( i+n,2*n+1,-2*x);
}
for ( int i=1,u,v; i<=m; i++ )
u=read(),v=read(),add( u+n,v,inf ),add( v+n,u,inf );
printf( "%d\n",ans-Dinic() );
}