Educational Codeforces Round 178 (Rated for Div. 2)

A. Three Decks

满足;两个条件即可:

  1. 总和是3的倍数
  2. c的值大于sum/3
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
//using i128 = __int128_t;
const ll inf = 1e18;
const int mod = 998244353;

void solve(){
    int a,b,c;
    cin>>a>>b>>c;
    int sum=0;

    sum=a+b+c;

    int t=sum/3;
    if(t*3!=sum){
        cout<<"NO\n";
        return;
    }

    if(a>t || b>t){
        cout<<"NO\n";
        return;
    }
    cout<<"YES\n";
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int ct=1;
    cin>>ct;
    while(ct--){
        solve();
    }

    return 0; 
}

B. Move to the End

对于每个下标为i的后缀,有两种情况:

  1. 不改变,答案为suf[i]
  2. 改变,可以把前i-1个数中的最大值换过来,答案为suf[i+1]+maxpre[i-1]
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
//using i128 = __int128_t;
const ll inf = 1e18;
const int mod = 998244353;

void solve(){
    int n;
    cin>>n;

    vector<int>a(n+10),pre(n+10),suf(n+10),sum(n+10);

    for(int i=1;i<=n;i++){
        cin>>a[i];
        pre[i]=max(pre[i-1],a[i]);
        sum[i]=sum[i-1]+a[i];
    }

    for(int i=n;i>=1;i--){
        suf[i]=max(suf[i+1],a[i]);
    }

    for(int k=1;k<=n;k++){
        int ans=sum[n]-sum[n-k];
        int tmp=sum[n]-sum[n-k+1]+pre[n-k+1];
        ans=max(ans,tmp);
        cout<<ans<<" ";
    }
    cout<<endl;

}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int ct=1;
    cin>>ct;
    while(ct--){
        solve();
    }

    return 0; 
}

C. Card Game

重点在于1和n上。
如果一个人同时持有1和n,则必胜。
如果Alice有1无n:

  1. 如果Bob只有n一张牌,则Alice必胜,因为Alice可以出1,Bob只能出n。
  2. 否则Bob胜,因为Alice无论出什么牌,Bob都有能战胜的牌。

如果Alice有n无1:

  1. 如果Alice只有n一张牌,则Bob必胜。
  2. 如果第n-1张牌是Bob的,则Bob必胜,因为如果Alice出n,Bob可以出1,如果Alice出其他牌,Bob可以出n-1。
  3. 否则Alice胜。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
//using i128 = __int128_t;
const ll inf = 1e18;
const int mod = 998244353;

void solve(){
    int n;
    cin>>n;
    string s;
    cin>>s;
    s=" "+s;

    int cnta=0,cntb=0;
    for(int i=1;i<=n;i++){
        if(s[i]=='A') cnta++;
        else cntb++;
    }

    if(s[1]==s[n]){
        if(s[1]=='A'){
            cout<<"Alice"<<endl;
        }else{
            cout<<"Bob"<<endl;
        }
        return;
    }else{
        if(s[1]=='A'){
            //Alice 有1无n
            if(cntb==1){
                cout<<"Alice"<<endl;
            }else{
                cout<<"Bob"<<endl;
            }

        }else{
            //Alice  有n无1
            if(cnta==1 || s[n-1]=='B'){
                cout<<"Bob"<<endl;
            }
            else{
                cout<<"Alice"<<endl;
            }
        }
    }
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int ct=1;
    cin>>ct;
    while(ct--){
        solve();
    }

    return 0; 
}

D. Array and GCD

赛时又花了一些时间看懂题干描述是什么意思

质数筛的模板还是错的,浪费了好长时间

首先,删除一些数之后的数组,是可以随意分配数值,且可以让总和变小的,只需要保证每个数不小于2.
所以一定要让每个数都是指数,为了每个数都能变成质数,则需要让这k个数的总和不大于前k个质数的总和
所以如果原数组的总和,大于前n个质数的总和,则删去最大数,直到符合条件。

题目需要筛出4e5的质数,而1-n范围内的质数大概有n/ln(n)个
我直接筛到了5e7,其实完全不用这么大

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
//using i128 = __int128_t;
const ll inf = 1e18;
const int mod = 998244353;
const int N=1e7;
const int M=4e5+10;

const int maxn = 1e8 + 5;
vector<int> Prime;
bool vis[maxn];

int pre[M];

void init() {
	vis[1] = 1;
    int n=maxn/2;
	for (int i = 2; i <= n; ++i) {
		if (vis[i] == 0)
			Prime.push_back(i);
		for (auto p : Prime) {
			if (i * p > n)
				break;
			vis[i * p] = 1;
			if (i % p == 0)
				break;
		}
	}
    pre[1]=2;
    for(int i=2;i<M;i++){
        pre[i]=pre[i-1]+Prime[i-1];
    }
}

void solve(){
    int n;
    cin>>n;
    vector<int> a(n+1);

    for(int i=1;i<=n;i++){
        cin>>a[i];
    }

    sort(a.begin()+1,a.end(),greater<int>());

    for(int i=1;i<=n;i++){
        a[i]+=a[i-1];
    }

    for(int i=n;i>=1;i--){
        if(a[i]>=pre[i]){
            cout<<n-i<<endl;
            return;
        }
    }


}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    init();

    int ct=1;
    cin>>ct;
    while(ct--){
        solve();
    }

    return 0; 
}

E. Unpleasant Strings

赛时见到题,还以为是什么奇奇妙妙的字符串算法题,觉得不可做于是直接去睡觉,哎,,

其实得到答案主要分两部分,第一部分是在主串中找到子串的子序列,第二部分是计算在第一步找到的子序列最后的位置,至少需要加几个字符,能保证一定跳出主串。

第一部分:

需要对主串每个位置i,处理出当前位置的下一个字符j所在的位置,记为next[i][j],这一步的代码实现从后往前处理即可,的复杂度是26n。
假设子串的第一个字符是j,则直接从next[0][j]开始,跳到子串的最后一个字符即可。

第二部分:

dp[i]表示从i开始,至少需要加几个字符才能跳出主串(跳到n+1的位置)。
状态转移非常好想,只要枚举下次跳到的字符j来更新dp值即可。枚举j:
dp[i] = min ( dp[ next[i][j] ] + 1 )

点击查看代码
#include<bits/stdc++.h>
// #define int long long
using namespace std;
using pii=pair<int,int>;
using ll=long long;
const ll inf=1e9;
const int mod =1e9+7;

void solve(){
    int n,k;
    cin>>n>>k;
    string s;
    cin>>s;

    s=" "+s;

    vector<vector<int>> ne(n+10,vector<int>(k+10));
    for(int i=1;i<=k;i++){
        ne[n+1][i]=n+1;
    }

    // 处理出每个位置的下一个字符1-k在哪里
    for(int i=n;i>=0;i--){
        for(int j=1;j<=k;j++){
            ne[i][j]=ne[i+1][j];
        }
        ne[i][s[i+1]-'a'+1]=i+1;
    }

    //dp[i]表示从这出发到n+1要走几步
    vector<int> dp(n+10,inf);
    dp[n+1]=0;

    for(int i=n;i>=0;i--){
        for(int j=1;j<=k;j++){
            dp[i]=min(dp[i],1+dp[ne[i][j]]);
        }
    }

    int q;
    cin>>q;

    while(q--){
        string t;
        cin>>t;

        int now=0;
        
        for(auto ch:t){
            now=ne[now][ch-'a'+1];
        }
        cout<<dp[now]<<endl;
    }
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    
    int ct=1;
    // cin>>ct;

    while(ct--){
        solve();
    }
    return 0;
}
posted @ 2025-04-29 23:41  LYET  阅读(42)  评论(0)    收藏  举报