Codeforces Round 908 (Div. 2) (思维 + 鸽巢原理+枚举)

A:赢得那个人肯定是最后一个人才结束

所以直接输出最后一个

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10,mod= 998244353;
#define int long long
typedef long long LL;
typedef pair<int, char> PII;

int n,m,k;
int a[N],s[N];
void solve()
{
    
    cin>>n;
    string s;
    cin>>s;
    cout<<s.back()<<"\n";
}

signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t=1;
    cin>>t;
    while(t--) solve();
}

B:

只要满足两个条件,所以只要有两对相同数字的就行

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10,mod= 998244353;
#define int long long
typedef long long LL;
typedef pair<int, char> PII;

int n,m,k;
vector<int> g[N];
int a[N];
int res[N];
void solve()
{
    for(int i=0;i<=100;i++)
    {
        g[i].clear();
    }
    cin>>n;
    int cnt=0;
    map<int,int> mp;
    for(int i=1;i<=n;i++){
        int x;
        cin>>x;
        mp[x]++;
        if(mp[x]==2) cnt++;
        g[x].push_back(i);
    }
    if(cnt<2){
        cout<<"-1\n";
        return ;
    }
    int now=0;
    
    for(int i=1;i<=100;i++)
    {
        if(g[i].empty()) continue;
        res[g[i][0]]=1;
        if(g[i].size()==1) continue;
        int tar=3;
        
        if(now==0) tar=2;
        now^=1;
        for(int j=1;j<g[i].size();j++){
            res[g[i][j]]=tar;
        }
    }
    for(int i=1;i<=n;i++)
    cout<<res[i]<<" \n"[i==n];
    
}

signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t=1;
    cin>>t;
    while(t--) solve();
}

C:

观察最后一个数,每次都是由最后一个数操作才得到当前序列的

所以直接从最后一个数开始枚举上去即可,如果出现环或者操作次数大于n就满足

举例子吧

比如 7 2 1 是由最后一个数1操作来的,所以上一个序列是

1 7 2

然后还是由最后一个数2操作来的,所以上一个序列是

7 2 1

然后继续由最后一个属1操作来的,所以上一个序列是

1 7 2

然后就循环了一直,因为它可以让a数组任意,所以只要次数或者有个环就能满足

每次数变成当前最后一个数即可

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10,mod= 998244353;
#define int long long
typedef long long LL;
typedef pair<int, char> PII;

int n,m,k;
vector<int> g[N];
int a[N];
int b[N];
void solve()
{
    cin>>n>>k;
    for(int i=0;i<n;i++){
        cin>>a[i];
    }
    int idx=n-1;
    map<int,int> mp;
    for(int i=1;i<=min(n,k);i++){
        if(a[idx]>n){
            cout<<"No\n";return ;
        }
        idx=(idx-a[idx]);
        idx=(idx+n)%n;
        if(mp[idx]>0){
            cout<<"Yes\n";
            return ;
        }
        mp[idx]++;
    }
    cout<<"Yes"<<"\n";
}

signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t=1;
    cin>>t;
    while(t--) solve();
}

D:

我是这样想的,让b数组随便插入而且还要非单调递增

所以肯定让b数组从大到小插入嘛

然后插入到a哪里呢,

肯定从a数组后面第一个出现的数a[i]插入比如a[i]小于等于的b[i]

比如

现在要插入6 

数组有

7  x x  7  x  x 7

你肯定直接插入到最后一个7后面嘛,毕竟越后面插入,中间用得到6的数更少

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10,mod= 998244353;
#define int long long
typedef long long LL;
typedef pair<int, char> PII;

int n,m,k;
vector<int> g[N];
int a[N];
int b[N];
void solve()
{
    cin>>n>>m;
    map<int,int> mp;
    for(int i=1;i<=n;i++){
        g[i].clear();
        cin>>a[i];
    }
    for(int i=1;i<=m;i++) cin>>b[i];
    sort(b+1,b+1+m);
    int idx=1;
   
    for(int i=n;i>=1;i--)
    {
        while(idx<=m&&a[i]>=b[idx])
        {
            g[i].push_back(b[idx]);
            idx++;
        }    
    }
     for(int i=m;i>=idx;i--) cout<<b[i]<<" ";
    for(int i=1;i<=n;i++){
        cout<<a[i]<<" ";
        sort(g[i].begin(),g[i].end(),greater<>());
        for(auto x:g[i]) cout<<x<<" ";
    }
   
    cout<<"\n";
}

signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t=1;
    cin>>t;
    while(t--) solve();
}

E:

这个题是个套路题,我见过好多次了...

直接枚举L 到 R的总和就行

因为n=10w,由于鸽巢原理,就是L到R总和很大,由于n的不同数有10w个

我10w个数枚举完后,当前数肯定没有的,然后个数取当前数就行了,答案肯定是0

否则,直接枚举数取当前值就行

然后就直接枚举就行

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10,mod= 998244353;
#define int long long
typedef long long ll;
typedef pair<int, int> pii;
const long long inf=1e17;
int n,m,k;
vector<int> g[N];
void solve()
{
    int m;cin>>m;
    
    //一维数字的值,二维{在哪出现,出现次数}
    map<int,vector<pii>>mp;
    vector<array<int,4>>e(m);
    int mnL=0,mxR=0;
    for(int i=0;i<m;i++){
        auto &[n,l,r,sum]=e[i];
        cin>>n>>l>>r;
        mnL+=l,mxR+=r;
        vector<int>a(n),c(n);
        for(int j=0;j<n;j++) cin>>a[j];
        for(int j=0;j<n;j++) cin>>c[j];
        for(int j=0;j<n;j++){
            sum+=c[j];
            mp[a[j]].push_back({i,c[j]});
        }
    }
 
    bool ok=1;
    for(int i=mnL;i<=mxR;i++){
        if(i>inf||!mp.count((ll)i)){
            ok=0;
            break;
        }
    }
 
    if(!ok){
        cout<<0<<'\n';
        return;
    }
 
    ll ans=inf;
    for(ll i=mnL;i<=mxR;i++){
        ll res=0;
        //假设都选r个数字
        ll s=mxR;
        for(auto &[id,cnt]:mp[i]){
            auto &[n,l,r,sum]=e[id];
            //还原成不选的状态
            s-=r;
            //最少选==i的数字的数量
            ll t=0;
            if(sum-cnt<l){
                t=l-(sum-cnt);
            }
            //最少选几个数,如果选数的数量不是r,剩下的数一定都是i
            s+=max(l,min(r,sum-cnt));
            res+=t;
        }
 
        //剩下的能选的数都是i,补上不够的数
        if(s<i) res+=i-s;
        ans=min(ans,res);
    }
    cout<<ans<<'\n';
}

signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t=1;
    cin>>t;
    while(t--) solve();
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值