Codeforces Round #778 (Div. 1 + Div. 2, based on Technocup 2022 Final Round)(ABCDE)

Posted 斗奋力努

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #778 (Div. 1 + Div. 2, based on Technocup 2022 Final Round)(ABCDE)相关的知识,希望对你有一定的参考价值。

Codeforces Round #778 (Div. 1 + Div. 2, based on Technocup 2022 Final Round)(ABCDE)

A. Maximum Cake Tastiness

题意:输出最大+次大的和

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1005;
int n,m,q,a[N];

void solve()
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    sort(a+1,a+n+1,greater<int>());
    printf("%d\\n",a[1]+a[2]);


int main()
    int T;scanf("%d",&T);
    while(T--) solve();
    return 0;

B. Prefix Removals
题意:如果首字符在字符串后面还有出现,就可以删除首字符,问最终字符串的形式
思路:先记录每个字符出现的次数,然后从前往后遍历,如果后面还有该字符,就该字符数量-1,否则结束,输出剩下字符串。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5;
char s[N];
int num[40];

void solve()
    for(int i=0;i<26;i++) num[i]=0;
    scanf("%s",s+1);
    int len=strlen(s+1);
    for(int i=1;i<=len;i++) num[s[i]-'a']++;
    int idx;
    for(int i=1;i<=len;i++)
        if(num[s[i]-'a']>1) num[s[i]-'a']--;
        else idx=i;break;
    
    for(int i=idx;i<=len;i++) printf("%c",s[i]);
    puts("");


int main()
    int T;scanf("%d",&T);
    while(T--) solve();
    return 0;

C. Alice and the Cake
题意:有一个蛋糕,切n-1刀,使蛋糕分成n份。每次去切蛋糕时,选择一块蛋糕大小w>=2的,切成 ⌊ w 2 ⌋ 和 ⌈ w 2 ⌉ ⌊w2⌋和⌈w2⌉ w2w2两部分。
现在给出最终n块小蛋糕的大小,问是否存在原蛋糕,满足切法后构成该n块小蛋糕。
思路:我们发现每次切蛋糕都是“平分”上一个蛋糕,总大小是不变的,所有初始序列a的总和就是原蛋糕的大小,然后我们去切蛋糕,同时记录每块蛋糕的大小,如果最终存在该大小就移除该蛋糕,问最终剩余蛋糕是否为0就行了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5;
ll n,sum;
vector<ll>now,tmp;
map<ll,int>mp;

void solve()
    sum=0;
    mp.clear();now.clear();tmp.clear();
    scanf("%lld",&n);
    for(ll i=1;i<=n;i++)
        ll x;scanf("%lld",&x);
        sum+=x;
        mp[x]++;
    
    now.push_back(sum);
    ll yu=n;
    while(yu>=now.size()&&now.size()&&yu)
        for(auto it:now)
            if(mp[it]) mp[it]--,yu--;
            else
                if(it>=2)
                    tmp.push_back(it/2);
                    tmp.push_back((it+1)/2);
                
                else tmp.push_back(1);
            
        
        now=tmp;
        tmp.clear();
    
    if(yu==0) puts("YES");
    else puts("NO");


int main()
    int T;scanf("%d",&T);
    while(T--) solve();
    return 0;

D. Potion Brewing Class
题意:有n个节点的一颗树,n-1条边,每边满足 a [ i ] / a [ j ] = x / y a[i]/a[j]=x/y a[i]/a[j]=x/y,问满足全部比例的树的最小权值和
思路:
由于比例可能是分数的形式,累乘起来分数形式可能比较大,不好操作。
所以我们当我们知道某个节点的值,剩下的去dfs就可以确定其他所有节点的值
这里我们确定节点1的值,我们拿其他所有点来跟节点1操作,通过变换公式,我们可以得到节点1的值,防止数太大,节点1的值分解质因数的形式表示,最后再暴力枚举质因子得到节点1的值 ( (%mod) (

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=2e5+5;
const ll mod=998244353;
ll n,ned[N],mxned[N],ans;
ll inv[N],prime[N],cnt,lst[N];
bool vis[N];
map<ll,ll>mp;
struct nodell v,x,y;;
vector<node>edge[N];

void init()
    //线性求逆元
    inv[1]=1;
    for(ll i=2;i<N;i++) inv[i]=(mod-mod/i)*inv[mod%i]%mod;

    //线性筛
    for(ll i=2;i<N;i++)
        if(!vis[i]) prime[++cnt]=i,mp[i]=cnt;
        for(ll j=1;i<N/prime[j];j++)
            vis[i*prime[j]]=true;
            if(i%prime[j]==0) break;
        
    


ll gcd(ll x,ll y)return !y?x:gcd(y,x%y);

void change(ll x,int type)
    for(ll i=1;i<=cnt;i++) //分解质因数
        ll num=prime[i];
        if(num*num>x) break;
        while(x%num==0)
            ned[i]=ned[i]+type;
            x/=num;
        
        mxned[i]=max(mxned[i],ned[i]); 
    
    if(x>1)
        ned[mp[x]]=ned[mp[x]]+type;
        mxned[mp[x]]=max(mxned[mp[x]],ned[mp[x]]);
    


void dfs1(ll u,ll fa)
    ll len=edge[u].size();
    for(ll i=0;i<len;i++)
        ll v=edge[u][i].v;
        if(v==fa) continue;
        ll x=edge[u][i].x,y=edge[u][i].y;
        change(y,-1);
        change(x,1);
        dfs1(v,u);
        change(x,-1);
        change(y,1);
    


void dfs2(ll u,ll fa,ll val)
    ll len=edge[u].size();
    ans=(ans+val)%mod;
    for(ll i=0;i<len;i++)
        ll v=edge[u][i].v,x=edge[u][i].x,y=edge[u][i].y;
        if(v==fa) continue;
        dfs2(v,u,val*y%mod*inv[x]%mod); //等价变换公式
    


void solve()
    scanf("%lld",&n);
    for(ll i=1;i<n;i++)
        ll u,v,x,y; scanf("%lld%lld%lld%lld",&u,&v,&x,&y);
        ll gd=gcd(x,y);
        x/=gd,y/=gd;
        edge[u].push_back(v,x,y);
        edge[v].push_back(u,y,x);
    
    dfs1(1,0);
    ll val_1=1;
    for(ll i=1;i<=cnt;i++) //暴力得到节点1的值
        for(ll j=1;j<=mxned[i];j++)
            val_1=(val_1*prime[i])%mod;
        
    
    dfs2(1,0,val_1); //知道节点1的值,去dfs2其他节点
    printf("%lld\\n",ans);

    ans=0;
    for(ll i=1;i<=cnt;i++) ned[i]=mxned[i]=0;
    for(ll i=1;i<=n;i++) edge[i].clear();


int main()
    init();
    int T;scanf("%d",&T);
    while(T--) solve();
    return 0;

E. Arithmetic Operations

题意:长度为n的序列,变换多少次,可以使得任意 ( 2 < = i < = n − 1 ) (2<=i<=n-1) (2<=i<=n1),满足 a [ i + 1 ] − a [ i ] = a [ i ] − a [ i − 1 ] a[i+1]-a[i]=a[i]-a[i-1] a[i+1]a[i]=a[i]a[i1]
思路:(典型的题意简单题目难)
我们发现最终序列一定会是一个等差数列,所以题目就变成了找原序列中最长等差子序列, n > = 1 e 5 n>=1e5 n>=1e5数据较大不会找。
枚举小公差 ( − 300 < = d < = 300 ) (-300<=d<=300) (300<=d<=300),用数组记录每个数字减去位置乘公差的值出现的次数,出现最多的次数就是在枚举范围内的最优解。
对于大公差,我们发现序列中不会出现特别多的满足条件的数 ( 1 < = a [ i ] < = 1 e 5 ) (1<=a[i]<=1e5) (1<=a[i]<=1e5)
m p [ i ] [ j ] mp[i][j] mp[i][j]:以i结尾的为d的边有多长。
找出两种情况的最优值mx,就是原序列中最长等差子序列,答案也是n-mx

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
int n,ans,a[N],d=300;
int b[N*300];

int go()
    int mx=0;
    以上是关于Codeforces Round #778 (Div. 1 + Div. 2, based on Technocup 2022 Final Round)(ABCDE)的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Round #436 E. Fire(背包dp+输出路径)

[ACM]Codeforces Round #534 (Div. 2)

Codeforces 778A:String Game(二分暴力)

CF778B(round 402 div.2 E) Bitwise Formula

CodeForces - 778C: Peterson Polyglot (启发式合并trie树)

CodeForces 778B - Bitwise Formula