首页 > 其他分享 >AGC021 解题笔记

AGC021 解题笔记

时间:2023-11-29 14:56:33浏览次数:35  
标签:ch ifac int 笔记 解题 IL AGC021 reg define

好久没写一整场 CF 或者 AT 的题解了,所以写一篇。

C

有点意思的题。

考虑先放横再放竖,若确定所有横的位置,那么每列独立。所以记 \(f_i\) 表示第 \(i\) 列最多放多少个,考虑放一个横对 \(f_i\) 的影响。

若 \(n\) 为奇数,那么第一行放满显然最优。若某时 \(A>1\),那么放一个 \(2\times 2\) 的形式一定最优。

现在有可能还剩下一个。记此时第一个可以放的位置为 \((x,y)\),若直接放这会使 \(f_y,f_{y+1}\) 均减一;而当 \(n,m\) 均为奇数的时候,放 \((x+1,m-1)\) 则会只让 \(f_m\) 减一。

那就做完了,复杂度 \(O(nm)\)。

#include<bits/stdc++.h>
#define IL inline
#define reg register
#define N 1010
int n,m,sa,sb;
char ans[N][N];

main()
{
    scanf("%d%d%d%d",&n,&m,&sa,&sb);
    for(reg int i=1,j;i<=n;++i)for(j=1;j<=m;++j)ans[i][j]='.';
    reg int x=1,y=1;
    if(m==1)goto skip;
    if(n&1)
    {
        while(y<m&&sa)--sa,ans[x][y]='<',ans[x][y+1]='>',y+=2;
        ++x,y=1;
    }
    while(x<n&&sa>1)
    {
        sa-=2,ans[x][y]=ans[x+1][y]='<';
        ans[x][y+1]=ans[x+1][y+1]='>',y+=2;
        if(y>=m)x+=2,y=1;
    }
    if(x<=n&&sa)--sa,ans[x+1][m-1]='<',ans[x+1][m]='>';
    skip:;
    if(sa)puts("NO"),exit(0);
    for(reg int j=1,i;j<=m;++j)for(i=1;i<n&&sb;++i)
        if(ans[i][j]=='.'&&ans[i+1][j]=='.')ans[i][j]='^',ans[i+1][j]='v',--sb;
    if(sb)puts("NO"),exit(0);
    puts("YES");
    for(reg int i=1,j;i<=n;++i,puts(""))for(j=1;j<=m;++j)putchar(ans[i][j]);
}

D

感觉比 C 简单很多。

直接嗯 dp 不太好做到太低的复杂度,考虑观察一点性质。

容易发现并证明,对于给定字符串,它的贡献为最长回文子序列。

那就可以直接区间 dp。复杂度 \(O(n^2k)\)。

#include<bits/stdc++.h>
#define IL inline
#define reg register
#define N 330
int n,k,f[N][N][N],ans;
char s[N];

IL void cmax(reg int &x,reg int y){x<y?x=y:0;}

main()
{
    scanf("%s%d",s+1,&k),n=strlen(s+1);
    for(reg int i=1,j;i<=n;++i)for(j=0;j<=k;++j)f[i][i][j]=-1,f[i][i+1][j]=0;
    for(reg int l=n,r,i,w;l;--l)for(r=l;r<=n;++r)for(i=0;i<=k;++i)
    {
        w=f[l][r][i];
        if(s[l]==s[r])cmax(ans,w+=2),cmax(f[l-1][r+1][i],w);
        else
        {
            cmax(ans,w),cmax(f[l-1][r][i],w),cmax(f[l][r+1][i],w);
            if(i<k)cmax(ans,w+=2),cmax(f[l-1][r+1][i+1],w);
        }
    }
    printf("%d\n",ans);
}

E

简单题。

对于一只变色龙,考虑其为红色的充要条件。

若红色比蓝色多,显然成立;若红色与蓝色一样多,要求最后一个位置为蓝色。

回到原问题,枚举红色数量 \(i\),则蓝色数量 \(j=k-i\)。

  • \(i\ge j+n\),那么答案显然为 \(\binom{k}{i}\)。

  • \(i>j\),会有 \(x=n-i+j\) 只变色龙蓝色与红色一样多。考虑他们最后一个蓝色的选取,显然选最后 \(x\) 个更优。这也就要求最后 \(x\) 个蓝色都能与前面的红色匹配,计数是经典的折线容斥。

  • \(i=j\),所有变色龙蓝色与红色一样多,那就没有变色龙可以处理最后的一些红色。所以要求多了一个第 \(k\) 个球为蓝色,这也是折线容斥。

时间复杂度 \(O(k)\)。

#include<bits/stdc++.h>
#define IL inline
#define reg register
#define mod 998244353
#define N 500500
IL int read()
{
    reg int x=0; reg char ch=getchar();
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x;
}

IL int Add(reg int x,reg int y){return x+y<mod?x+y:x+y-mod;}
IL int Sub(reg int x,reg int y){return x<y?x-y+mod:x-y;}
IL void Pls(reg int &x,reg int y){x=Add(x,y);}
IL void Dec(reg int &x,reg int y){x=Sub(x,y);}
IL int Mul(reg int x,reg int y){reg long long r=1ll*x*y; return r<mod?r:r%mod;}

int fac[N],ifac[N],inv[N];

IL void init(reg int n)
{
    fac[0]=ifac[0]=inv[1]=1;
    for(reg int i=2;i<=n;++i)inv[i]=Mul(mod-mod/i,inv[mod%i]);
    for(reg int i=1;i<=n;++i)fac[i]=Mul(fac[i-1],i),ifac[i]=Mul(ifac[i-1],inv[i]);
}

IL int C(reg int n,reg int m){return n>=m&&m>=0?Mul(fac[n],Mul(ifac[m],ifac[n-m])):0;}

int n,m,ans;

main()
{
    n=read(),m=read(),init(5e5);
    for(reg int i=(m+1)/2,j;i<=m;++i)
    {
        j=m-i;
        if(i-j>=n)Pls(ans,C(m,i));
        else if(i>j)n<=i?Pls(ans,Sub(C(m,i),C(m,i+i-n+1))),0:0;
        else n<=i?Pls(ans,Sub(C(m-1,i),C(m-1,i+i-n+1))),0:0;
    }
    printf("%d\n",ans);
}

F

没那么简单的简单题。

由于 A 影响的都是前缀,所以考虑逐列确定。

第 \(j\) 列放区间 \([b_j,c_j]\) 时,考虑第 \(i\) 行的影响。

  • \(a_i<j\),可以任意作为端点。

  • \(a_i>j\),不能作为端点。

  • \(a_i=j\),\(i\in [b_j,c_j]\)。

注意到上述第二类事实上对答案没有影响,方案数事实上只需要将其他两类归并起来即可。

记 \(f_{i,j}\) 表示第 \(i\) 列时,有 \(j\) 个这两类的行。转移枚举第三类个数,系数通过区间包含的组合意义不难推导。

直接暴力 dp 为 \(O(n^2m)\),但注意到所有转移都是卷积的形式,可以优化到 \(O(nm\log n)\)。

#include<bits/stdc++.h>
#define IL inline
#define reg register
#define mod 998244353
#define N 40040
IL int read()
{
    reg int x=0; reg char ch=getchar();
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x;
}

IL int Add(reg int x,reg int y){return x+y<mod?x+y:x+y-mod;}
IL int Sub(reg int x,reg int y){return x<y?x-y+mod:x-y;}
IL void Pls(reg int &x,reg int y){x=Add(x,y);}
IL void Dec(reg int &x,reg int y){x=Sub(x,y);}
IL int Mul(reg int x,reg int y){reg long long r=1ll*x*y; return r<mod?r:r%mod;}
IL int power(reg int x,reg int p){reg int r=1; for(;p;p>>=1,x=Mul(x,x))if(p&1)r=Mul(r,x); return r;}

int fac[N],ifac[N],inv[N];

IL void init(reg int n)
{
    fac[0]=ifac[0]=inv[1]=1;
    for(reg int i=2;i<=n;++i)inv[i]=Mul(mod-mod/i,inv[mod%i]);
    for(reg int i=1;i<=n;++i)fac[i]=Mul(fac[i-1],i),ifac[i]=Mul(ifac[i-1],inv[i]);
}

int a[N],b[N],r[N],len,val[N+N];

IL void prework(reg int n)
{
    for(len=1;len<=n;len<<=1);
    for(reg int i=1;i<len;++i)r[i]=r[i>>1]+(i&1)*len>>1;
}

IL void dft(reg int *f)
{
    for(reg int i=len;i--;)if(r[i]>i)std::swap(f[i],f[r[i]]);
    for(reg int k=2,i,j,x,y;k<=len;k<<=1)for(i=0;i<len;i+=k)for(j=i;j<i+k/2;++j)
        x=f[j],y=Mul(f[j+k/2],val[k+j-i]),f[j]=Add(x,y),f[j+k/2]=Sub(x,y);
}

IL void idft(reg int *f)
{
    dft(f),std::reverse(f+1,f+len);
    for(reg int i=len,inv=mod-(mod-1)/len;i--;)f[i]=Mul(f[i],inv);
}

int n,m,f[N],g[N],ans;

main()
{
    n=read(),m=read(),init(n),f[0]=1;
    for(reg int k=2,i,w;k<N;k<<=1)
    {
        w=power(3,(mod-1)/k),val[k]=1;
        for(i=1;i<k/2;++i)val[k+i]=Mul(val[k+i-1],w);
    }
    prework(n+n);
    for(reg int i=1,j;i<=m;++i)
    {
        for(j=0;j<=n;++j)
        {
            g[j]=Mul(j+1,f[j]);
            if(j)Pls(g[j],Mul(j,f[j-1]));
        }
        memset(a,0,len<<2),memset(b,0,len<<2);
        for(j=0;j<=n;++j)a[j]=Mul(f[j],j>1?ifac[j-2]:0),b[j]=ifac[j+2];
        dft(a),dft(b);
        for(j=len;j--;)a[j]=Mul(a[j],b[j]);
        idft(a);
        for(j=0;j<=n;++j)Pls(g[j],Mul(fac[j],a[j]));

        memset(a,0,len<<2),memset(b,0,len<<2);
        for(j=0;j<=n;++j)a[j]=Mul(f[j]*2,j?ifac[j-1]:0),b[j]=j?ifac[j+1]:0;
        dft(a),dft(b);
        for(j=len;j--;)a[j]=Mul(a[j],b[j]);
        idft(a);
        for(j=0;j<=n;++j)Pls(g[j],Mul(fac[j],a[j]));

        memset(a,0,len<<2),memset(b,0,len<<2);
        for(j=0;j<=n;++j)a[j]=Mul(f[j],ifac[j]),b[j]=j>1?ifac[j]:0;
        dft(a),dft(b);
        for(j=len;j--;)a[j]=Mul(a[j],b[j]);
        idft(a);
        for(j=0;j<=n;++j)Pls(g[j],Mul(fac[j],a[j])),f[j]=g[j],g[j]=0;
    }
    for(reg int i=0;i<=n;++i)Pls(ans,Mul(f[i],Mul(ifac[i],ifac[n-i])));
    printf("%d\n",Mul(ans,fac[n]));
}

标签:ch,ifac,int,笔记,解题,IL,AGC021,reg,define
From: https://www.cnblogs.com/Nesraychan/p/17863231.html

相关文章

  • Opencv学习笔记(2)
    图像处理是图像识别过程中重要一环,一张图像可能包括海量的不明确的信息,图像处理的目的是消除图像中无关的信息,恢复有用的真实信息,增强有效信息的可检测性,最大限度地简化数据。参考知乎文章链接:https://zhuanlan.zhihu.com/p/547096645主要学习图像处理的一些手段和方法1、图像......
  • Linux vi 和 vim编辑器(学习笔记)
    1简介所有的Linux系统都会内建vi文本编辑器。vim具有程序编辑的能力,可以看做是vi的增强版本,可以主动的以字体颜色辨别语法的正确性,方便程序设计。代码补完、编译及错误跳转等方便编程的功能特别丰富,在程序员中被广泛使用。2vi和vim常用的三种模式2.1 正常模式以vim打开一......
  • 《Effective Java》阅读笔记-第三章
    EffectiveJava阅读笔记第三章对于所有对象都通用的方法第10条重写equals时请遵守通用约定重写equals方法很简单,但是很容易出现错误,最直接避免这种错误的方式就是不重写equals,当出现任意一下情况的时候,就不需要重写equals:类的每个实例在逻辑上就是唯一的没比要......
  • linux常用命令(学习笔记)
    1findfind.-name"*.c"//将目前目录及其子目录下所有延伸档名是c的文件列出来find.-typef//将目前目录其其下子目录中所有一般文件列出find.-ctime-20//将目前目录及其子目录下所有最近20天内更新过的文件列出find/var/log-typef-mtime......
  • Linux系统管理(学习笔记)
    1防火墙操作serviceiptablesstatus//查看iptables服务的状态serviceiptablesstart//开启iptables服务serviceiptablesstop//停止iptables服务serviceiptablesrestart//重启iptables服务chkconfigiptablesoff//关闭iptables服务......
  • 学习笔记434—【Matlab】Matlab读取dcm图像的函数
    【Matlab】Matlab读取dcm图像的函数Matlab版本:2020a一、dicomread函数Matlab读取dcm图像的函数是dicomread,根据dicomread的帮助文档,该函数有四种参数输入方式:X=dicomread(filename);%根据文件名直接读取X=dicomread(info);%根据构造的info结构体读取X=dicomrea......
  • Linux文件操作(学习笔记)
    文件操作1新增文件(touch)toucha.txt//在当前目录下创建名为a的txt文件(文件不存在),如果文件存在,将文件时间属性修改为当前系统时间2删除文件(rm)rm文件名//删除当前目录下的文件rm-f文件名//删除当前目录的的文件(不询问)3编辑文件(vi、vim)vi文件名//打开......
  • 初识Linux学习笔记
    引言作为一名计算机专业的学生,深入了解和熟练使用Linux操作系统是至关重要的。Linux在计算机领域有着广泛的应用,不论是服务器端还是嵌入式系统,都离不开Linux的支持。本文将介绍我个人初识Linux的学习经验,包括基本概念、常用命令以及一些实际应用。什么是Linux?Linux是一种开源的类U......
  • 第七周阅读笔记|人月神话————提纲挈领
    所谓提纲挈领,从字面上讲就是抓住渔网的总绳,提起衣服的领子,其含义(度娘说要用含义而不推荐用涵义)就是告诉我们做事情要能够抓住要领。那么本篇告诉我们什么是要领呢,就是书面文档,从一开始就要意识到其重要性,那么就不会对文档产生厌烦。因为作为技术人员来说,包括我,普遍对文档没有好感,......
  • Programming Abstractions in C阅读笔记:p202-p234
    《ProgrammingAbstractionsinC》学习第65天,p202-p234总结。一、技术总结完成第五章学习,第五章介绍递归在实际问题中的进一步应用,例如汉诺塔问题,数学中的排列问题,更有难度。使用递归解决问题时有时候需要借助wrapperfunction。二、英语总结1.scrabble是什么意思?答:*sker-("tocu......