首页 > 其他分享 >AtCoder Grand Contest 024

AtCoder Grand Contest 024

时间:2023-09-27 19:14:48浏览次数:32  
标签:AtCoder return 024 int Contest -- lt ans include

A - Fairness

每次操作后 \(a_i-b_i=b_{i-1}-a_{i-1}\),对 \(k\) 的奇偶性讨论一下即可。


#include<iostream>
#include<cstdio>
using namespace std;
int a,b,c;
long long k;
int main()
{
    scanf("%d%d%d%lld",&a,&b,&c,&k);
    if(k%2==0) printf("%d",a-b);
    else printf("%d",b-a);
    return 0;
}

B - Backfront

可以发现,最优策略肯定是选定一个区间,这个区间中的数在 \(p\) 中的位置单调递增。区间中的数不动,其他数字分别按照大小放到头尾,扫一遍找这个区间就好了。


#include<iostream>
#include<cstdio>
using namespace std;
const int N=200005;
int n;
int p[N];
int a[N];
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&p[i]);
    for(int i=1;i<=n;i++)
        a[p[i]]=i;
    int cnt=0,res=0;
    for(int i=1;i<=n;i++)
        if(a[i]>a[i-1]) cnt++,res=max(res,cnt);
        else cnt=1;
    printf("%d",n-res);
    return 0;
}

C - Sequence Growing Easy

首先如果存在 \(i\) 使得 \(a_i\ge i\) 或 \(a_i\gt a_{i-1}+1\) 显然不可能。

对于一个位置 \(i\),可以将 \(i-a_i+1\) 到 \(i\) 依次操作。如果存在 \(j\lt i\) 且 \(j-a_j+1=i-a_i+1\),我们可以直接从 \(j\) 继承过来。

扫一遍就完了。


#include<iostream>
#include<cstdio>
using namespace std;
const int N=200005;
int n;
int a[N];
int pre[N];
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)
        if(a[i]>=i||a[i]>a[i-1]+1)
        {
            printf("-1");
            return 0;
        }
    long long ans=0;
    for(int i=1;i<=n;i++)
    {
        if(pre[i-a[i]+1]) ans+=i-max(pre[i-a[i]+1],i-a[i]);
        else ans+=a[i];
        pre[i-a[i]+1]=i;
    }
    printf("%lld",ans);
    return 0;
}

D - Isomorphism Freak

可以发现,颜色数最少时树肯定是以某一个点或某一个边为根,深度相同的点的子树同构。

枚举每个点或每个边为根,取个最优的答案。


#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
const int N=105;
int n;
int u[N],v[N];
vector<int>G[N];
long long c[N];
int mx[N];
int dep[N];
void dfs(int u,int father)
{
    dep[u]=dep[father]+1;
    c[dep[u]]++;
    int tot=0;
    for(int v:G[u])
    {
        if(v==father) continue;
        dfs(v,u);
        tot++;
    }
    mx[dep[u]]=max(mx[dep[u]],tot);
    return;
}
pair<int,long long>solven(int s)
{
    for(int i=1;i<=n;i++)
        mx[i]=-1,c[i]=0;
    dfs(s,0);
    int cnt=0;
    for(int i=1;i<=n;i++)
        if(c[i]) cnt++;
    for(int i=1;i<n;i++)
        if(c[i]&&c[i+1]) c[i+1]=c[i]*mx[i];
    long long ans=1;
    for(int i=n;i>=1;i--)
        if(c[i])
        {
            ans=c[i];
            break;
        }
    return {cnt,ans};
}
pair<int,long long>solvee(int s,int t)
{
    for(int i=1;i<=n;i++)
        mx[i]=-1,c[i]=0;
    {
        dep[s]=1;
        c[dep[s]]++;
        int tot=0;
        for(int v:G[s])
        {
            if(v==t) continue;
            dfs(v,s);
            tot++;
        }
        mx[dep[s]]=max(mx[dep[s]],tot);
    }
    {
        dep[t]=1;
        c[dep[t]]++;
        int tot=0;
        for(int v:G[t])
        {
            if(v==s) continue;
            dfs(v,t);
            tot++;
        }
        mx[dep[t]]=max(mx[dep[t]],tot);
    }
    int cnt=0;
    for(int i=1;i<=n;i++)
        if(c[i]) cnt++;
    for(int i=1;i<n;i++)
        if(c[i]&&c[i+1]) c[i+1]=c[i]*mx[i];
    long long ans=1;
    for(int i=n;i>=1;i--)
        if(c[i])
        {
            ans=c[i];
            break;
        }
    return {cnt,ans};
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&u[i],&v[i]);
        G[u[i]].emplace_back(v[i]);
        G[v[i]].emplace_back(u[i]);
    }
    pair<int,long long>res={n+1,0LL};
    for(int i=1;i<=n;i++)
        res=min(res,solven(i));
    for(int i=1;i<n;i++)
        res=min(res,solvee(u[i],v[i]));
    printf("%d %lld",res.first,res.second);
    return 0;
}

E - Sequence Growing Hard

\(a_i\) 相当于在 \(a_{i-1}\) 某个数前面加入一个不小于它的数的前面即可。

但这样会算重,在 \(a_{i-1}\) 某个数前面加入一个大于它的数的前面就可以去重。

如果第 \(i\) 次操作插入的数,如果在第 \(j\) 次操作插入的数的左边,令 \(j\) 是 \(i\) 的父亲,我们就可以得到一棵 \(n+1\) 个点的数(令根节点为 \(0\)),每个点有一个 \([0,n]\) 的编号和一个 \([0,k]\) 之间的权值,这棵树的编号和权值都是一个严格小根堆。我们只需要计算这棵树的方案数就好了。

令 \(f_{i,j}\) 表示 \(i\) 个点的数,根节点的权值为 \(j\) 的方案数,其中根节点的编号为 \(0\)。枚举编号为 \(1\) 的子树大小转移:

\[f_{i,j}=\sum\limits_{l=1}^{i-1}f_{i-l,j}C_{i-2}^{l-1}\sum\limits_{v=j+1}^kf_{l,v} \]

后缀和优化一波就好了。


#include<iostream>
#include<cstdio>
using namespace std;
const int N=305;
int n,m;
int MOD;
int C[N][N];
int f[N][N];
int s[N][N];
int main()
{
    scanf("%d%d%d",&n,&m,&MOD);
    for(int i=0;i<=n;i++)
    {
        C[i][0]=1;
        for(int j=1;j<=i;j++)
            C[i][j]=(C[i-1][j]+C[i-1][j-1])%MOD;
    }
    for(int i=0;i<=m;i++)
        f[1][i]=1;
    for(int i=m;i>=0;i--)
        s[1][i]=(s[1][i+1]+f[1][i])%MOD;
    for(int i=2;i<=n+1;i++)
    {
        for(int j=0;j<=m;j++)
            for(int k=1;k<i;k++)
                f[i][j]=(f[i][j]+1LL*f[i-k][j]*C[i-2][k-1]%MOD*s[k][j+1])%MOD;
        for(int j=m;j>=0;j--)
            s[i][j]=(s[i][j+1]+f[i][j])%MOD;
    }
    printf("%d",f[n+1][0]);
    return 0;
}

F - Simple Subsequence Problem

考虑类似子序列自动机的思想,每次将匹配剩下的串找到第一个 \(0/1\),删去这个前缀,然后在已匹配串后面加入一个 \(0/1\),这样匹配的方案是唯一的。

如果待匹配串是原串的子序列,在原串做上述过程中一定有一个时刻已匹配串等于待匹配串。

考虑 DP,令 \(f_{S,T}\) 表示已匹配串为 \(S\),匹配剩下的串为 \(T\) 时原串的方案数。初始时令 \(f_{\varepsilon,C}=1\,(C\in S)\)。

因为 \(S+T\le n\),所以复杂度是对的。

转移分成三种情况:

  • 在 \(T\) 找到第一个 \(0\),删去开头到这个位置的所有字符,在 \(S\) 后面加入一个 \(0\)。
  • 在 \(T\) 找到第一个 \(1\),删去开头到这个位置的所有字符,在 \(S\) 后面加入一个 \(1\)。
  • 停止匹配,既将 \(T\) 置为空串。

对于一个串 \(S\),它作为 \(S\) 中字符串的子串的个数即为 \(f_{S,\varepsilon}\)。枚举每个串取最优即可。


#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
const int N=20;
int n,k;
string s[N+1];
int nxt[N+1][1<<N][2];
vector<vector<int>>f[2][1<<N];
int main()
{
    cin>>n>>k;
    for(int i=0;i<=n;i++)
        cin>>s[i];
    int cur=0;
    f[cur][0].resize(n+1);
    for(int i=0;i<=n;i++)
        f[cur][0][i].resize(1<<i);
    for(int i=0;i<=n;i++)
        for(int j=0;j<(1<<i);j++)
            if(s[i][j]=='1') f[cur][0][i][j]++;
    for(int i=0;i<=n;i++)
        for(int S=0;S<(1<<i);S++)
        {
            nxt[i][S][0]=-1;
            for(int j=i-1;j>=0;j--)
                if(!(S&(1<<j)))
                {
                    nxt[i][S][0]=j;
                    break;
                }
            nxt[i][S][1]=-1;
            for(int j=i-1;j>=0;j--)
                if(S&(1<<j))
                {
                    nxt[i][S][1]=j;
                    break;
                }
        }
    int la=0,ans=0;
    for(int ls=0;ls<=n;ls++)
    {
        for(int S=0;S<(1<<ls);S++)
            f[cur^1][S].clear();
        if(ls+1<=n)
        {
            for(int S=0;S<(1<<(ls+1));S++)
            {
                f[cur^1][S].resize(n-(ls+1)+1);
                for(int lt=0;lt<=n-(ls+1);lt++)
                    f[cur^1][S][lt].resize(1<<lt);
            }
        }
        for(int S=0;S<(1<<ls);S++)
            for(int lt=n-ls;lt>=0;lt--)
                for(int T=(1<<lt)-1;T>=0;T--)
                    if(f[cur][S][lt][T])
                    {
                        int v=f[cur][S][lt][T];
                        if(lt==0)
                        {
                            if(v>=k)
                            {
                                if(ls>la) la=ls,ans=S;
                                else if(ls==la) ans=min(ans,S);
                            }
                            continue;
                        }
                        int f0=nxt[lt][T][0];
                        if(f0!=-1) 
                        {
                            int s0=S<<1,t0=T&((1<<f0)-1);
                            f[cur^1][s0][f0][t0]+=v;
                        }
                        int f1=nxt[lt][T][1];
                        if(f1!=-1)
                        {
                            int s1=(S<<1)|1,t1=T&((1<<f1)-1);
                            f[cur^1][s1][f1][t1]+=v;
                        }
                        f[cur][S][0][0]+=v;
                    }
        cur^=1;
    }
    for(int i=la-1;i>=0;i--)
        if(ans&(1<<i)) cout<<"1";
        else cout<<"0";
    return 0;
}

标签:AtCoder,return,024,int,Contest,--,lt,ans,include
From: https://www.cnblogs.com/zhou-jk/p/17733475.html

相关文章

  • AtCoder Grand Contest 021
    A-DigitSum2要么是\(n\)要么是\(n\)的第一位后面加上若干个\(9\)。#include<iostream>#include<cstdio>#include<cmath>usingnamespacestd;longlongn;intcalc(longlongx){if(x==0)return0;intsum=0;while(x)sum+=x......
  • AtCoder Regular Contest 102
    C-TriangularRelationship枚举\(a\bmodk\)的值,\(b\bmodk,c\bmodk\)的值也就确定了,算下贡献就好了。#include<iostream>#include<cstdio>usingnamespacestd;intn,k;intmain(){ scanf("%d%d",&n,&k); longlongans=0; for(inta=0;......
  • ACL Contest 1
    A-ReachableTowns现把城市按照\(x_i\)排序将第一维去掉。对于每个联通块,将单调栈将每个联通块中\(y_i\)最小的那个存下来。每次新加入一个点\(i\)相当于前面的\(\lty_i\)的位置合并成一个联通块。具体地,将单调栈中所有\(\lty_i\)的点弹出,并查集合并一下,加入弹出......
  • AtCoder Regular Contest 103
    C-////如果奇数和偶数出现的颜色的最大值相同一边取最大值和一边取次大值,否则两边都选最大值即可。#include<iostream>#include<cstdio>#include<algorithm>usingnamespacestd;constintN=100005;intn,m;intv[N];intc[N];intmain(){ scanf("%d",&n); for(in......
  • DISCO Presents Discovery Channel Code Contest 2020 Qual
    A-DDCCFinals直接模拟即可。#include<iostream>#include<cstdio>usingnamespacestd;intx,y;intmain(){ scanf("%d%d",&x,&y); intans=0; if(x==1)ans+=30; elseif(x==2)ans+=20; elseif(x==3)ans+=10; if(y==1)ans+=30; ......
  • 2023-2024-1 20231402 《计算机基础与程序设计》第1周学习总结
    2023-2024-120231402《计算机基础与程序设计》第1周学习总结作业信息班级2023-2024-1-计算机基础与程序设计作业要求2023-2024-1计算机基础与程序设计第1周作业作业目标浏览教材并提出问题作业正文https://www.cnblogs.com/lsh0815/p/17731540.html教材学习中提出的问......
  • diverta 2019 Programming Contest
    A-ConsecutiveIntegers答案为\(n-k+1\)。#include<iostream>#include<cstdio>usingnamespacestd;intn,k;intmain(){ scanf("%d%d",&n,&k); printf("%d",n-k+1); return0;}B-RGBBoxes枚举\(r,g\),判断一下对应的......
  • AtCoder Grand Contest 048
    A-atcoder<S枚举操作完的串\(s\)和atcoder相同的前缀长度,算出前面的前缀相同的代价加上当前这位大于atcoder中对应的那一位的代价即为达到当前状态的代价,取个最小值即可。#include<iostream>#include<cstdio>#include<cstring>usingnamespacestd;constintN=1......
  • AtCoder Grand Contest 046
    A-Takahashikun,TheStrider问题就是要你求\(ax\equiv0\pmod{360}\)中\(a\)的最小值。答案就是\(a=\frac{360}{\gcd(x,360)}\)。代码:#include<iostream>#include<cstdio>usingnamespacestd;intx;intgcd(inta,intb){ returnb==0?a:gcd(b,a%b);......
  • AtCoder Grand Contest 047
    A-IntegerProduct考虑将原来的数全部化为整数,乘上\(10^9\),那么问题就变成了是否有两个数的乘积是\(10^{18}\)的倍数。考虑如果是\(10^{18}\)的倍数的话必然是\(2^{18}\)和\(5^{18}\)的倍数,那么分解出每个数的\(2,5\)因子数量,然后再看看有多少个数与它\(2,5\)的因......