cf(1034)Div3(补题A B C D E F)

哈,这个比赛在开了不久之后,不知道为啥卡了差不多20来分钟,后面卡着卡着就想睡觉了。实在是太困了....

题目意思:

Alice做一次操作,删除任意数字a,而Bob做一次操作删除b使得a+b对4取余是3。

获胜条件,有人不能再进行操作,则另一个人获胜。

思路:

A题嘛,直接胆大心细,观察样例给的数据,得出,仅当给出的数是4的倍数的时候Bob获胜。

其他情况下嘛,Alice获胜。

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n;cin>>n;
    //质数
    while(n--){
        int x;cin>>x;
        if(x%4==0){
            cout<<"Bob"<<endl;
        }
        else{
            cout<<"Alice"<<endl;
        }
    }
}

 

题目意思:

给定一个数组,a[i]是i选手的战斗力,当剩余选手超过k名的时候:

随机选择两个选手,淘汰实力较低的那一个,如果实力一样的话,随便淘汰一个。

问是否存在一种操作方式,使得j选手可以成为剩下的那k个。

思路:

首先我们对k进行分析,k=1的时候直接特判,此时第j名选手只有最大才能宝珠。

当k>=2的时候,我们给出一个样例:

1 2 3 4 5 6

此时我们对上述数据进行若干次操作后发现,任意数据都能存活。

那么同理,如果有相同数据的话,也可以共存。

#include<bits/stdc++.h>
using namespace std;
inline void solve(){
    int n,j,k;cin>>n>>j>>k;
    vector<int>a(n+1);
    int mi=-1;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        mi=max(a[i],mi);
    }
    if(k>=2){
        //两种情况
        cout<<"Yes"<<endl;
        return;
    }
    int ans=a[j];
    //此时要是整个数组里面最大的那一个
    if(ans==mi&&k==1){
        cout<<"Yes"<<endl;
    }
    else{
        cout<<"No"<<endl;
    }
}
int main(){
    int n;cin>>n;
    //质数
    while(n--){
        solve();
    }
}

 题目意思:

给定一个数组,可以做一次操作:

1.选择一个前缀a,并替换成最小值

2.选择一个后缀a,并替换成最大值

到最后数组里面只剩下最后一个数字,如果该数字对应第i个字符,则第i个字符为1,否则为0,

输出01字符串。

思路:

用两个数组,一个维护前缀最小值,一个维护后缀最大值,最后判断原数组是否与该两个数组中的任意一个相等即可。

其实他的原理就是根据题目的意思,维护前缀和后缀。

#include <bits/stdc++.h>
using namespace std;

inline void solve() {
    int n;cin>>n;
    vector<int>a(n+1);
    vector<int>pre(n+1,8e18),suf(n+2);
    //pre维护的是前缀
    //suf维护的是后缀
    for(int i=1;i<=n;i++){
        cin>>a[i];
        pre[i]=min(pre[i-1],a[i]);
    }
    for(int i=n;i>=1;i--){
        suf[i]=max(suf[i+1],a[i]);
    }
    for(int i=1;i<=n;i++){
        cout<<(a[i]==pre[i]||a[i]==suf[i]?1:0);
    }
    cout<<endl;

}

int main() {
    int t;
    cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}

 题目意思:

给定一个字符串和两个操作:

Alice操作一次,选择任意k个位置将其变成0

Bob操作一次,选择连续k个位置将其变成1

问,在有限的操作次数内,是否能将整个字符串都变成0。

思路:

我们先对

7 4

1011011

这个数据进行分析

此时Alice进行一次操作

0001000

后Bob在进行一次操作(有多个可能性)

1111000

0011110

0001111

此时我们发现在这种情况下,Alice必胜,必胜的条件在于k,k必须是要大于等于n/2+1,此时刚好整个数组被覆盖的时候中间有重叠的部分。

最后在特判一下第一次Alice就能把数组恢复原状的情况即可。

#include <bits/stdc++.h>
using namespace std;

inline void solve() {
    int n,k;cin>>n>>k;
    string ac;cin>>ac;
    int answer=n/2+1;
    int sum=0;
    ac=' '+ac;
    for(int i=1;i<=n;i++){
        if(ac[i]=='1')sum++;
    }
    //一遍就能把数组恢复原状
    if(sum<=k){
        cout<<"Alice"<<endl;
        return;
    }
    if(k<answer){
        cout<<"Bob"<<endl;
        return;
    }
    cout<<"Alice"<<endl;
    return;
}

int main() {
    int t;
    cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}

题目意思:

 定义MEX为数组中没有出现的最小非负数,如

MEX([2, 2, 1]) = 0,因为0不在数组中。

计算从a数组中删除k个值之后,MEX可能值的数量。(0<=k<=n)

思路:

首先我们先肯定一个事情k=0,和k=n一定是固定的,一定是1。

其次我们在考虑k等于1的时候可以从k=0考虑,同理后推。

此时我们发现,当存在多个相同的数字的时候,相同数字的数量成为了我们要考虑的一个点,从这个切口出发,我们构造一个差分数组即可。

#include <bits/stdc++.h>
using namespace std;
void solve(){
    int n;
    cin >> n;
    vector<int> a(n), answer(n+1), suf(n+2);
    map<int, int> p;
    for(int i=0; i<n; i++){
        cin >> a[i];
        p[a[i]]++;
        //统计各个数字出现的次数
    }
    for(int i=0; i<=n; i++){
        suf[p[i]]++;//统计次数出现的次数,并且往后进行自减
        suf[n-i+1]--;
        //差分
        if(!p[i])
            //当前数组中没有这个数字的话,直接跳出
            break;
    }
    for(int k=0; k<=n; k++){
        answer[k] = (k ? answer[k-1] : 0) + suf[k];
        //和我们之前说的一样,后面的k受前者k的影响
        cout << answer[k] << (k != n ? ' ' : '\n');
    }
}

int main(){
    int t;
    cin >> t;
    while(t--) solve();
}

题目意思:

我们定义一个好数组,对于所有的i>=2,gcd(i,pi)!=1。

构造一个这样的数组,并使得固定点最少。(固定点:当i=p[i])

思路:

其实样例已经给我们一些提示了,下标为2的数字,对应的是4,下标是4的数字对应的是2,而质数下的数字对应的是自己本身。(暂且我们只能从样例中看出这么些情况)

随后我们自己再枚举一些比较大的数据发现,质数i对应的可以是i*2,i*3,i*4....而i*2对应的可以是i*3,i*4...此时我们可以发现,这些数字(gcd=i)形成了一个环,每个数字只要对应的找到下一个数字即可满足gcd!=1的情况。

故:

我们只要先对质数进行预处理,再对每一个质数环进行赋值即可。

最后的最后,还有一个点就是如果从小素数开始遍历,小素数的倍数会覆盖更多的数(因为小素数的倍数更密集),导致后续大素数的倍数可能已经被分配到其他循环中。
如果从大素数开始遍历,大素数的倍数更稀疏,可以优先构建较大的循环,而小素数的倍数可以填充剩余的数。

从大的素数开始遍历可以使得固定点更小。

#include<bits/stdc++.h>
using namespace std;
#define int long long
vector<bool>cmp(1e5+3);
vector<int>zhi;
const int op=1e5+4;
void init(){
    // 埃拉托斯特尼筛法预计算素数
    for(int i=2;i*i<=op;i++){
        if(!cmp[i]){
            for(int j=i*i;j<=op;j+=i){
                cmp[j]=1;
            }
        }
    }
    for(int i=2;i<=op;i++)if(!cmp[i])zhi.push_back(i);
}
void solve(){
    int n;cin>>n;
    vector<int>answer(n+1);
    //cout<<*zhi.rbegin()<<endl;
    for(auto it=zhi.rbegin();it<zhi.rend();it++){
        //只能从后往前
        vector<int>c;
        for(int i=*it;i<=n;i+=*it){
            //在n这个范围内
            if(!answer[i]){
                c.push_back(i);
            }
        }
        for(int i=0;i<c.size();i++){
            answer[c[i]]=c[(i+1)%c.size()];
        }
    }
    /*
    for(int i=1;i<=n;i++){
        if(!answer[i]){
            answer[i]=i;
        }
    }
    */
    answer[1]=1;
    for(int i=1;i<=n;i++){
        cout<<answer[i]<<(i!=n?' ':'\n');
    }
    return;
}
signed main(){
    init();
    int n;cin>>n;
    while(n--)solve();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值