Codeforces Round #772 (Div. 2)(ABCDE)

Posted 斗奋力努

tags:

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

Codeforces Round #772 (Div. 2)(ABCDE)

A. Min Or Sum

题意:给一个长度为n的序列,可以多次进行操作,每次选择不同的i,j,使得满足 a [ i ] ∣ a [ j ] = x ∣ y a[i]|a[j]=x|y a[i]a[j]=xy,x、y任意,问最后序列的最小总和。
思路:因为可以一直或操作 a [ i ] ∣ a [ j ] = x ∣ y a[i]|a[j]=x|y a[i]a[j]=xy也可以看成为变化后 a [ i ] + a [ j ] a[i]+a[j] a[i]+a[j]的值。所以我们只要看所有数在二进制下的哪些位是1就行了,最后加起来就是答案

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=105;
ll n,sum,bit[35];

void solve()
    sum=0;
    for(ll i=0;i<=30;i++) bit[i]=0;
    scanf("%lld",&n);
    for(ll i=1;i<=n;i++)
        ll x;scanf("%lld",&x);
        for(ll j=0;j<=30;j++)
            ll y=(x>>j)&1;
            if(y==1) bit[j]++;
        
    
    for(ll i=0;i<=30;i++)
        if(bit[i]!=0) sum+=(1ll<<i);
    
    printf("%lld\\n",sum);


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

B. Avoid Local Maximums

题意:给你一个长度为n的序列,问最少经过多少次变换,保证没有局部最大值。局部最大值定义为严格大于两边的值。所有第一位和最后一位一定不能成为局部最大值。要求输出最少次数和变化后的序列。
思路:我们从2遍历到n-1,如果第i个数满足局部最大值的条件,我们就去变化i+1位置的数,这样变化最少。
变化最好是可以使得位置i、i+1、i+2当不能成为局部最大值。所以a[i+1]=max(a[i],a[i+2]。
(我初始加了边界 a [ n + 1 ] = 1 e 9 a[n+1]=1e9 a[n+1]=1e9,可以不加)

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

void solve()
    sum=0;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    a[n+1]=1e9;
    for(int i=2;i<n;i++)
        if(a[i]>a[i-1]&&a[i]>a[i+1])
            sum++;
            a[i+1]=max(a[i],a[i+2]);
        
    
    printf("%d\\n",sum);
    for(int i=1;i<=n;i++) printf("%d%c",a[i],(i==n)?'\\n':' ');


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

C. Differential Sorting

题意:给一个长度为n的序列,可以进行m次操作 ( 0 < = m < = n ) (0<=m<=n) (0<=m<=n),每次操作选定一个三元组x,y,z, ( 1 < = x < y < z < = n ) (1<=x<y<z<=n) (1<=x<y<z<=n),将 a [ x ] = a [ y ] − a [ z ] a[x]=a[y]-a[z] a[x]=a[y]a[z]。问是否可以最终将序列变成一个非降序列。不能输出-1,可以输出操作数和具体操作方案
思路:首先,必须保证 a [ n − 1 ] < = a [ n ] a[n-1]<=a[n] a[n1]<=a[n],因为这两处的值无法更改,让从后往前遍历,找到第一个非负数(位置idx),因为一个数减去一个负数,会使值增加,我们找到非负数,遍历时发现 a [ i ] > a [ i + 1 ] a[i]>a[i+1] a[i]>a[i+1],我们就可以选择i,i+1,idx,这样就可以使得 a [ i ] < = a [ i + 1 ] a[i]<=a[i+1] a[i]<=a[i+1]

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+5;
int n,a[N];
struct nodeint x,y,z;;
vector<node>ans;

void solve()
    ans.clear();
    scanf("%lld",&n);
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
    if(a[n]<a[n-1])puts("-1");return;
    int idx=-1;
    if(a[n]>=0) idx=n;
    else if(a[n-1]>=0) idx=n-1;
    for(int i=n-2;i>=1;i--)
        if(a[i]<=a[i+1]) continue;
        else
            if(idx==-1) puts("-1");return;
            ans.push_back(i,i+1,idx);
            a[i]=a[i+1]-a[idx];
        
    
    int len=ans.size();
    printf("%lld\\n",len);
    for(int i=0;i<len;i++) printf("%lld %lld %lld\\n",ans[i].x,ans[i].y,ans[i].z);


signed main()
    int t;scanf("%lld",&t);
    while(t--) solve();

D. Infinite Set
题意:给定n个不同的数,可以进行两种操作,就所有出现的数放入一个set,问值小于 2 p 2^p 2p的元素个数,答案 m o d 1 e 9 + 7 mod1e9+7 mod1e9+7
思路:

/*
    看做二进制数
    操作1:x*2+1 相当于 x1 加一位1
    操作2:x*4 相当于x00 加两位0
    并且任何数y都只可能由一种数转移而来不存在有两个数x1,x2进行若干次操作都可以得到y(x1,x2不能互相得到)
    所以长度为len的二进制数可以由len-1的数进行操作1得到,由长度为len-2的数进行操作2得到,不会重复计算
    另外有一些数不可能由以上操作得到 即 x为偶数且不是4的倍数,只能作为ai出现在集合里
    或者能衍生出它的数不存在ai中,这些数单独计算
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=2e5+5;
const ll mod=1e9+7;
ll n,p,a[N],dp[N];
map<int,bool>mp;

int main()
    scanf("%lld%lld",&n,&p);
    for(ll i=1;i<=n;i++) scanf("%lld",&a[i]);
    sort(a+1,a+n+1);
    for(ll i=1;i<=n;i++)
        ll now=a[i];
        while(1)
            if(now==1) break;
            if(mp[now]) break;
            if(now%2==1) now/=2;
            else if(now%4==0) now/=4;
            else break;
        
        if(mp[now]) continue;
        else
            mp[a[i]]=true;
            ll len=0;
            while((1ll<<len)<a[i]) len++;
            if((1ll<<len)==a[i]) dp[len+1]++;
            else dp[len]++;
        
    
    for(ll i=1;i<=p;i++) dp[i]=(dp[i]+dp[i-1]+dp[i-2])%mod;
    ll sum=0;
    for(ll i=1;i<=p;i++) sum=(sum+dp[i])%mod;
    printf("%lld\\n",sum);

E. Cars
题意和思路在代码块内

//在水平线上有n辆车。有m种限制,每种限制为type,x,y
//当type==1时,第x辆车和第y辆车不能相遇
//当type==2时,第x辆车和第y辆车必须相遇一次
//问是否有方式,确定小车方向后,以及初始小车位置,使得满足所有限制
//先二分图匹配看是否存在方式,同时用point记录点的关系信息。point[i]存的都是必须在第i辆车右边的车的编号
//因为速度任意,所有不管是否相遇,方向都要相反
//col[i]==1:第i辆车向右 --->
//col[i]==0:第i辆车向左 <---

/*注释①
col[u]==1&&type==2  
第u辆车方向向右(--->),此时第v辆车必须和第u辆车相遇,且已知第v辆车方向向左(<---)
那么第v辆车一定是在第u辆车的右边。 情况(--u->  <-v--)

col[u]==0&&type==1
第u辆车方向向左(<---),此时第v辆车必须和第u辆车不能相遇,且已知第v辆车方向向右(--->)
那么第v辆车一定是在第u辆车的右边。 情况(<-u--  --v->)

*/

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,m,col[N],pos[N],in[N],now;
bool vis[N],flag=true;
vector<int>point[N],nodes;
vector<pair<int,int> >edge[N];

void dfs1(int u,int color)
    if(!flag) return;
    nodes.push_back(u);
    col[u]=color;
    int len=edge[u].size();
    for(int i=0;i<len;i++)
        int type=edge[u][i].first;
        int v=edge[u][i].second;
        if(col[u]==col[v]) flag=false;return;
        if((col[u]==1&&type==2)||(col[u]==0&&type==1)) point[u].push_back(v); //上面注释①
        else point[v].push_back(u);
        if(col[v]==-1) dfs1(v,color^1);
    


void dfs2(int u)
    if(!flag) return;
    in[u]=1;vis[u]Codeforces Round #772 (Div. 2)(ABCDE)

Codeforces Round #772 (Div. 2)(ABCDE)

DP二进制Codeforces Round #772 (Div. 2) D.Infinite Set

DP二进制Codeforces Round #772 (Div. 2) D.Infinite Set

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

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