Codeforces Round #767 (Div. 2)(A B C D E F1 F2)

Codeforces Round #767 (Div. 2)(A B C D E F1 F2)

A. Download More RAM
在这里插入图片描述题意:问最多可以有多大RAM,当前RAM大于等于a[i]时,可以使RAM增加b[i]
思路:暴力+贪心,就将n个RAM参照a[i]从小到大排序就行了。

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int>PII;
const int N=1005;
int n,k;
PII a[N];

void solve(){
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++) scanf("%d",&a[i].first);
    for(int i=1;i<=n;i++) scanf("%d",&a[i].second);
    sort(a+1,a+n+1);
    for(int i=1;i<=n;i++){
        if(k>=a[i].first) k+=a[i].second;
    }
    printf("%d\n",k);
}

int main(){
    int t;scanf("%d",&t);
    while(t--) solve();
}

B. GCD Arrays
在这里插入图片描述题意:在区间[l,r]中所有整数构成的集合中进行k次操作,每次操作是选择集合中的两次数,将他们删去,把他们的乘积加入集合。问最后集合所有数的gcd是否大于1
思路:因为初始是连续的数,所有我就直接猜了一下当集合中的奇数个数小于等于k时,或者集合初始只有一个数时(需要特判掉这个),就是YES,否则就是NO。(好像是保证奇偶结合还是啥的)

#include<bits/stdc++.h>
using namespace std;
int l,r,k;

void solve(){
    scanf("%d%d%d",&l,&r,&k);
    int len;
    if(l%2==1) len=(r-l+2)/2;
    else len=(r-l+1)/2;
    if(k>=len) puts("YES");
    else if(l==r&&l!=1) puts("YES");
    else puts("NO");
}

int main(){
    int t;scanf("%d",&t);
    while(t--) solve();
}

C. Meximum Array在这里插入图片描述
题意:给一个长度为n的序列a,每次从开头取一截数字,将该截数字删去,同时在b序列中加入这截数字的MEX,要求输出字典序最大的b序列

思路:直接记录每种数字的位置,循环时拿now代表当前需要的数字,①:如果还有该数字,就代表可以选到now,则now+1,去讨论now+1是否还存在now+1,同时用p记录本次取数(1~now)要到达的最右端 p = m a x ( p , p o s [ n o w ] . b a c k ( ) ) , n o w + + ; p=max(p,pos[now].back()),now++; p=max(p,pos[now].back()),now++;
②:如果没有该数字了,则将now加入b序列,同时将数字(1~now-1)中所有小于p位置的数去掉,这是本次使用过的,同时将now=0重新开始循环。
结束后要是now还有值,也需要加入b序列,应该取到最后没有数了,也没有将now置为0,即此时还在一个循环中。
最后一次循环的右端点后面还有多少数就加多少个0到b序列

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,a[N],num[N];
vector<int>ans;
vector<int>pos[N];

void solve(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        int x;scanf("%d",&x);
        pos[x].push_back(i);
    }
    for(int i=0;i<=n;i++) reverse(pos[i].begin(),pos[i].end());
    int now=0,p=0;
    while(pos[0].size()){
        if(pos[now].size()) p=max(p,pos[now].back()),now++;
        else{
            ans.push_back(now);
            for(int i=0;i<now;i++){
                while(pos[i].size()&&pos[i].back()<=p) pos[i].pop_back();
            }
            now=0;
        }
    }
    if(now) ans.push_back(now);
    for(int i=0;i<=n;i++){
        while(pos[i].size()&&pos[i].back()<=p) pos[i].pop_back();
        while(pos[i].size()) ans.push_back(0),pos[i].pop_back();
    }
    int len=ans.size();
    printf("%d\n",len);
    for(int i=0;i<len;i++) printf("%d%c",ans[i],(i==len-1)?'\n':' ');
    ans.clear();
}

int main(){
    int t;scanf("%d",&t);
    while(t--) solve();
}

D. Peculiar Movie Preferences
在这里插入图片描述
题意:在n个字符串中,按顺序选择一些字符串,能否构成回文串。
思路:每个字符串的长度<=3,所以拿map记录,暴力循环就行了。
可以的情况有
一个字符串:
①存在长度为1的字符串 (如a、b、c…)
②存在形如AA的字符串(如aa、bb、cc…)
③存在形如ABA或AAA的字符串(如aaa、aba、aca…)
两个字符串:
④2+2,即形如AB+BA(如ab+ba)
⑤2+3,即形如AB+CBA或AB+BBA(如ab+cba、ab+bba)
⑥3+2,即形如ABC+BA或ABB+BA(如abc+ba、abb+ba)
⑦3+3,即形如ABC+CBA或ABB+BBA(如abc+cba、abb+bba)
以上都不存在,则一定是没有了。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,flag;
string s[N];
map<string,int>mp;

void input(){
    flag=false,mp.clear();
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>s[i];
        int len=s[i].length();
        if(len==1) flag=true; //单个字母
        else if(len==2){
            if(s[i][0]==s[i][1]) flag=true;//类似aa的形式
        }
        else{
            if(s[i][0]==s[i][2]) flag=true;//类似aba的形式
        }
    }
}

void solve(){
    input();
    if(flag) {puts("YES");return;}
    for(int i=1;i<=n;i++){
        int len=s[i].length();
        if(len==2){
            string nows;
            nows.push_back(s[i][1]);
            nows.push_back(s[i][0]);
            if(mp.find(nows)!=mp.end()){puts("YES");return;}
            for(int j=0;j<26;j++){
                string tes;
                tes+=nows;
                tes.push_back(j+'a');
                if(mp.find(tes)!=mp.end()){puts("YES");return;}
            }
            mp[s[i]]=1;
        }
        else{
            string nows1;
            nows1.push_back(s[i][2]);
            nows1.push_back(s[i][1]);
            nows1.push_back(s[i][0]);
            if(mp.find(nows1)!=mp.end()){puts("YES");return;}    
            string nows2;
            nows2.push_back(s[i][2]);
            nows2.push_back(s[i][1]);        
            if(mp.find(nows2)!=mp.end()){puts("YES");return;}
            mp[s[i]]=1;
        }
    }
    puts("NO");
}

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

E. Grid Xor
在这里插入图片描述
题意:给定一个n*n的矩阵,矩阵中点(i,j)的值为其四周的格子的异或值组成,要我们求所有格子的的数的异或值。保证n是偶数
思路:发现当某个点的四周都还未加入异或值时,选择该位置的数,就可以将四周没加入数加入异或值,发现在n为偶数时一定成立。(具体证明过程自证,我是画图找规律得出的)

#include<bits/stdc++.h>
using namespace std;
const int N=1005;
int n,a[N][N];
int dx[]={-1,1,0,0};
int dy[]={0,0,-1,1};

void solve(){
    scanf("%d",&n);
    memset(a,0,sizeof(a));
    int sum=0;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            int x;scanf("%d",&x);
            bool flag=true;
            for(int k=0;k<4;k++){
                int nx=i+dx[k];
                int ny=j+dy[k];
                if(a[nx][ny]!=0){flag=false;break;}
            }
            if(flag){
                for(int k=0;k<4;k++){
                    int nx=i+dx[k];
                    int ny=j+dy[k];
                    a[nx][ny]=1;
                }
                sum^=x;
            }
        }
    }
    printf("%d\n",sum);
}

int main(){
    int t;scanf("%d",&t);
    while(t--) solve();
}

F1. Game on Sum (Easy Version)
在这里插入图片描述
题意:n轮游戏,每轮一个数,可以加上或减去,但至少加上的轮数要是m轮,每个数的范围为[0,k]的实数,问最终得分多少
思路:n的范围2000,可以 O ( n m ) O(nm) O(nm)
d p [ i ] [ j ] 代 表 剩 下 i 轮 选 择 , 还 需 要 做 j 次 加 法 的 得 分 dp[i][j]代表剩下i轮选择,还需要做j次加法的得分 dp[i][j]ij
d p [ i ] [ j ] = m i n ( x + d p [ i − 1 ] [ j − 1 ] , − x + d p [ i − 1 ] [ j ] ) dp[i][j]=min(x+dp[i-1][j-1],-x+dp[i-1][j]) dp[i][j]=min(x+dp[i1][j1],x+dp[i1][j])
d p [ i ] [ j ] = ( d p [ i − 1 ] [ j − 1 ] + d p [ i − 1 ] [ j ] ) / 2 dp[i][j]=(dp[i-1][j-1]+dp[i-1][j])/2 dp[i][j]=(dp[i1][j1]+dp[i1][j])/2

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
ll n,m,k,dp[2005][2005];
ll ksm(ll a,ll b){
    ll res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}

void solve(){
    scanf("%lld%lld%lld",&n,&m,&k);
    ll inv=500000004;//inv=ksm(2,mod-2);
    for(ll i=1;i<=n;i++){
        dp[i][i]=i*k%mod;
        for(ll j=1;j<i;j++){
            dp[i][j]=(dp[i-1][j]+dp[i-1][j-1])*inv%mod;
        }
    }
    cout<<dp[n][m]%mod<<"\n";
}

int main(){
    int t;scanf("%d",&t);
    while(t--) solve();
}

F2. Game on Sum (Hard Version)

题意:跟F1一样,只有数据范围变成了 1 e 6 1e6 1e6

思路:根据dp我们发现其实过程类似杨辉三角,答案为 ( i + 1 , i ) (i+1,i) (i+1,i) ( n , m ) (n,m) (n,m)的路径数乘上 2 ( − l e n ) 2^(-len) 2(len)乘上i,最后再乘上k就是答案
需要特判掉n==m的情况。(具体证明过程之后有时间补上)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=1e6+6;
const ll mod=1e9+7;
const ll inv=500000004;//ksm(2,mod-2)
ll n,m,k;
ll fact[N],infact[N];

ll ksm(ll a,ll b){
    ll res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}

ll C(ll a,ll b){return (fact[a]*infact[b]%mod*infact[a-b])%mod;}

void solve(){
    scanf("%lld%lld%lld",&n,&m,&k);
    ll sum=0;
    if(n==m) sum=n;
    else{
        for(ll i=1;i<=m;i++){
            sum=(sum+i*C(n-i-1,m-i)%mod*ksm(inv,n-i))%mod;
        }
    }
    printf("%lld\n",sum*k%mod);
}

void build(){
    fact[0]=infact[0]=1;
    for(ll i=1;i<N;i++){
        fact[i]=fact[i-1]*i%mod;
        infact[i]=ksm(fact[i],mod-2);
    }
}

int main(){
    build();
    int t;scanf("%d",&t);
    while(t--) solve();
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值