AtCoder Regular Contest 107

Contest Link
Official Editorial

比赛体验良好,网站全程没有挂。题面简洁好评,题目质量好评。对于我这个蒟蒻来说非常合适的一套题目。

A. Simple Math

Problem Link

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

\[\sum_{a=1}^A\sum_{b=1}^B\sum_{c=1}^C a\times b\times c = \sum_{a=1}^A a\sum_{b=1}^B b\sum_{c=1}^C c \]

疯狂取模就好了。

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

Problem Link

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\) 的方案数。于是得到:

\[f(N,K)=\min(K-1,2\times N+1-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

Problem Link

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

Problem Link

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

Problem Link

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

Problem Link

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() );
}
posted @ 2020-11-17 19:39  MontesquieuE  阅读(180)  评论(0编辑  收藏  举报