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

AtCoder Grand Contest 026

时间:2023-09-27 19:15:58浏览次数:39  
标签:AtCoder return string Contest int res 026 include MOD

A - Colorful Slimes 2

可以发现,对于连续的一段长度为 \(m\) 的相同的字符,我们可以花费 \(\lfloor \frac{m}{2}\rfloor\) 的代价将它改为符合要求的。


#include<iostream>
#include<cstdio>
using namespace std;
const int N=105;
int n;
int a[N];
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    int ans=0;
    for(int i=1,j=1;i<=n;i=j)
    {
        while(j<=n&&a[j]==a[i]) j++;
        ans+=(j-i)/2;
    }
    printf("%d",ans);
    return 0;
}

B - rng_10s

不妨设我们买了 \(x\) 次果汁,补了 \(y\) 次果汁。

问题相当于判 \(c\lt a-bx+dy\lt b\) 是否有整数解。

移下项,可以化成 \(a-c\lt bx-dy\lt a-b\)。

由裴蜀定理可知 \(\gcd(b,d)|bx-dy\),那么这题就做完了。


#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int T;
long long a,b,c,d;
void solve()
{
    scanf("%lld%lld%lld%lld",&a,&b,&c,&d);
    if(a<b||d<b)
    {
        printf("No\n");
        return;
    }
    long long t=__gcd(b,d);
    long long x=(a-b+t)/t*t;
    if(a-b<x&&x<a-c) printf("No\n");
    else printf("Yes\n");
    return;
}
int main()
{
    scanf("%d",&T);
    while(T--)
        solve();
    return 0;
}

C - String Coloring

直接 meet-in-middle 就完了。


#include<iostream>
#include<cstdio>
#include<map>
using namespace std;
const int N=40;
int n;
char s[N];
map<pair<string,string>,int>vis;
void dfs1(int u,string r,string b)
{
    if(u>n)
    {
        vis[{r,b}]++;
        return;
    }
    dfs1(u+1,r+s[u],b);
    dfs1(u+1,r,b+s[u]);
    return;
}
long long ans;
void dfs2(int u,string r,string b)
{
    if(u<=n)
    {
        ans+=vis[{r,b}];
        return;
    }
    dfs2(u-1,r+s[u],b);
    dfs2(u-1,r,b+s[u]);
    return;
}
int main()
{
    scanf("%d",&n);
    scanf("%s",s+1);
    dfs1(1,"","");
    dfs2(2*n,"","");
    printf("%lld",ans);
    return 0;
}

D - Histogram Coloring

可以发现,如果当前行中有两个相邻的位置颜色相同,它上面的那行肯定是这行的颜色取反,否则上面那行要么跟这行相同,要么是这行取反。

那么对于区间 \([l,r]\),我们需要求出它在 \(now\) 行及以上填色,且 \(now\) 存在两个相邻的位置颜色相同或不存在两个相邻的位置颜色相同的方案数。可以按照最小值分治,转化成若干个子问题递归即可。


#include<iostream>
#include<cstdio>
using namespace std;
const int N=105;
const int MOD=1000000007;
int n;
int h[N];
int ksm(int a,int b)
{
    int res=1;
    while(b)
    {
        if(b&1) res=1LL*res*a%MOD;
        a=1LL*a*a%MOD,b>>=1;
    }
    return res;
}
pair<int,int>solve(int l,int r,int now)
{
    int mi=1e9;
    for(int i=l;i<=r;i++)
        mi=min(mi,h[i]);
    int cnt=0;
    for(int i=l;i<=r;i++)
        if(h[i]==mi) cnt++;
    if(cnt==r-l+1)
    {
        return {(ksm(2,r-l+1)-2+MOD)%MOD,ksm(2,mi-now+1)};
    }
    int s0=1,s1=2;
    for(int i=l,j=l;i<=r;i=j)
    {
        if(h[i]==mi)
        {
            while(j<=r&&h[j]==mi) j++;
            s0=1LL*s0*ksm(2,j-i)%MOD;
        }
        else
        {
            while(j<=r&&h[j]>mi) j++;
            pair<int,int>s=solve(i,j-1,mi+1);
            s0=1LL*s0*(s.first+2LL*s.second)%MOD;
            s1=1LL*s1*s.second%MOD;
        }
    }
    s0=((long long)s0-s1+MOD)%MOD;
    s1=1LL*s1*ksm(2,mi-now)%MOD;
    return {s0,s1};
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&h[i]);
    int res=1;
    for(int i=1;i<=n;i++)
        if(h[i]>h[i-1]&&h[i]>h[i+1])
        {
            res=1LL*res*ksm(2,h[i]-max(h[i-1],h[i+1]))%MOD;
            h[i]=max(h[i-1],h[i+1]);
        }
    pair<int,int> ans=solve(1,n,1);
    res=1LL*res*(ans.first+ans.second)%MOD;
    printf("%d",res);
    return 0;
}

E - Synchronized Subsequence

可以将尽可能多的将 \(S\) 分割成若干段,最后从后往前贪心合并移下就好了。

考虑每段里面怎么处理,可以分成两种情况:

如果 \(\forall i \in [1,n],a_i\lt b_i\),则最后的字符串一定是 ababab 的形式。

如果 \(\forall i \in [1,n],b_i\lt a_i\),则我们肯定是选定一个找到某个 \(i\),删去 \(i\) 的后面的 \(a_i,b_i\)。因为如果你考虑当前留下了一段 b 的前缀,如果你要删掉某个 a,那么删掉这个 a 及其前面的 b 以后的字符串肯定继续将删去的那个 a 后面的 a 删去更优。


#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
int n;
string s;
string solve(int l,int r)
{
    string t=s.substr(l,r-l+1);
    int m=t.size();
    if(t.front()=='a')
    {
        vector<int>a,b;
        vector<int>pos(m);
        for(int i=0;i<m;i++)
            if(t[i]=='a') a.emplace_back(i),pos[i]=a.size()-1;
            else b.emplace_back(i),pos[i]=b.size()-1;
        string res="ab";
        int now=b[0];
        for(int i=1;i<m/2;i++)
            if(a[i]>now) res+="ab",now=b[i];
        return res;
    }
    else
    {
        vector<int>a,b;
        vector<int>pos(m);
        for(int i=0;i<m;i++)
            if(t[i]=='a') a.emplace_back(i),pos[i]=a.size()-1;
            else b.emplace_back(i),pos[i]=b.size()-1;
        string res="";
        for(int i=0;i<=m/2;i++)
        {
            string str;
            for(int j=0;j<m;j++)
                if(pos[j]>=i) str+=t[j];
            res=max(res,str);
        }
        return res;
    }
}
int main()
{
    cin>>n;
    cin>>s;
    int cnt=0;
    string res;
    for(int j=2*n-1,i;j>=0;j=i)
    {
        if(s[j]=='a') cnt++;
        else cnt--;
        i=j-1;
        while(i>=0&&cnt!=0)
        {
            if(s[i]=='a') cnt++;
            else cnt--;
            i--;
        }
        string t=solve(i+1,j);
        res=max(res,t+res);
    }
    cout<<res;
    return 0;
}

F - Manju Game

令 \(B\) 为奇数位置的和,\(W\) 为偶数位置的和。

当 \(n\) 为偶数时,先手开始时走 \(1\) 和 \(n\) 处可以得到 \(B\) 分和 \(W\) 分,先手至少可以得到 \(\max(B,W)\) 分;后手可以将先手得分控制在 \(\max(B,W)\) 以内,所以先手的得分为 \(\max(B,W)\),后手的得分为 \(\min(B,W)\)。

当 \(n\) 为奇数时,同理先手如果走 \(1\) 或 \(n\) 可以得到 \(B\) 分,如果先手要使得分数大于 \(B\) 第一步必须走偶数位置。当先手走到偶数位置后,后手玩家可以选择该位置的一侧,先手玩家得到该侧的 \(W\) 分,游戏在另一侧继续。

考虑先手的决策树,每个节点对应一个区间 \([l,r]\) 表示先手玩家走在的偶数位置,若不存在,则表示先手玩家选择得到 \(B\) 分,结束游戏。后手可以决定走到左子树还是右子树。

可以发现,对于一棵给定的决策树,后手玩家可以决定在哪个叶子结束游戏。所以先手玩家需要最大化所有结束区间的 \(B-W\) 的最小值,二分答案后相当于是判断能否找出若干个偶数点,让这些点之间的 \(B-W\ge mid\)。


#include<iostream>
#include<cstdio>
using namespace std;
const int N=300005;
int n;
int a[N];
int s[N];
bool check(int x)
{
    int pre=0;
    for(int i=2;i<=n;i+=2)
        if(s[i-1]-pre>=x) pre=min(pre,s[i]);
    return s[n]-pre>=x;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    int w=0,b=0;
    for(int i=1;i<=n;i++)
        if(i%2==1) b+=a[i],s[i]=s[i-1]+a[i];
        else w+=a[i],s[i]=s[i-1]-a[i];
    if(n%2==0) printf("%d %d",max(w,b),min(w,b));
    else
    {
        int l=-w-b,r=w+b,ans=0;
        while(l<=r)
        {
            int mid=(l+r)/2;
            if(check(mid)) ans=mid,l=mid+1;
            else r=mid-1;
        }
        printf("%d %d",w+ans,b-ans);
    }
    return 0;
}

标签:AtCoder,return,string,Contest,int,res,026,include,MOD
From: https://www.cnblogs.com/zhou-jk/p/17733472.html

相关文章

  • AtCoder Grand Contest 022
    A-DiverseWord如果至少有一个字符没有出现过,只要在原字符串后面加入一个没有出现过的字符中最小的那个字符就好了。如果所有字符都出现过,找到一个尽量靠后的位置\(i\in[1,n)\),使得\(s_i\lts_{i+1}\),最优字符串将\(s_i\)换成\([i+1,n]\)里面比\(s_i\)大的最小的那个......
  • AtCoder Grand Contest 023
    A-Zero-SumRanges令\(s_n=\sum\limits_{i=1}^na_i\),相当于找满足\(l\ler,s_r-s_{l-1}\)的点对\((l,r)\)的个数,直接搞就完事了。#include<iostream>#include<cstdio>#include<unordered_map>usingnamespacestd;constintN=200005;intn;inta[N]......
  • AtCoder Grand Contest 024
    A-Fairness每次操作后\(a_i-b_i=b_{i-1}-a_{i-1}\),对\(k\)的奇偶性讨论一下即可。#include<iostream>#include<cstdio>usingnamespacestd;inta,b,c;longlongk;intmain(){scanf("%d%d%d%lld",&a,&b,&c,&k);if(k%2==0)......
  • 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; ......
  • 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......