【题目记录】——Codeforces Round #772 (Div. 2)


题目集地址 Codeforces Round #772 (Div. 2)

A Min Or Sum

题目大意:给一个长度为n的序列a,执行如下操作
用x替换 a i a_i ai用y替换 a j a_j aj,保证 a i ∣ a j a_i|a_j aiaj=x|y,
问执行任意次以上操作后整个序列的和最小是多少?
思路:对于任意的 a i , a j a_i,a_j aiaj,令x= a i ∣ a j a_i|a_j aiaj,都可以替换为x和0,最后将所有的数字替换过后,最终数组只剩下所有数字的或的值和0,最后的和就是所有数字的或的值

#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
int a[200];
void solve()
{
    int n;
    scanf("%d",&n);
    int sum=0;
    for(int i =1;i <= n;i++)
    {
        scanf("%d",a+i);
        sum=sum|a[i];
    }
    cout << sum << endl;
}

int main()
{
//	freopen("in.txt","r",stdin);
	int t = 1;
	scanf("%d",&t);
	while(t--)
	{
		solve();
	}
    return 0;
}

B Avoid Local Maximums

题目大意:给定一个数组,可以将其中任意一个数字替换成1到1e9的任意值,问最少执行几次操作可以实现数组中不存在Local maximums。
关于local maximums的定义是,KaTeX parse error: Expected 'EOF', got '&' at position 12: a_i>a_{i-1}&̲&a_i>a{i+1} a 1 和 a n a_1和a_n a1an永远不是local maximums
思路:遍历数组的值,同时进行判断,如果a[i]是一个local maximums,那么将a[i+1]修改为max(a[i],a[i+2])即可。
代码:

#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
const int N=2e5+5;
int a[N];
void solve()
{
    int n;
    scanf("%d",&n);
    for(int i = 1;i <= n;i++)
    {
        scanf("%d",a+i);
    }
    int cnt=0;
    if(n==2)
    {
        cnt=0;
    }
    else{
        for(int i= 2;i <n;i++)
        {
            if(a[i]>a[i-1]&&a[i]>a[i+1])
            {
                if(i+2<n)
                {
                    a[i+1]=max(a[i],a[i+2]);
                }
                else{
                    a[i+1]=a[i];
                }
                cnt++;
            }
        }
    }
    printf("%d\n",cnt);
    for(int i = 1;i <= n;i++)
    {
        if(i<n)
        printf("%d ",a[i]);
        else
        {
            printf("%d\n",a[i]);
        }
    }
}

int main()
{
//	freopen("in.txt","r",stdin);
	int t = 1;
	scanf("%d",&t);
	while(t--)
	{
		solve();
	}
    return 0;
}

C Differential Sorting

题目大意:给一个长度为n的数组,你可以执行以下操作不超过n次:选三个数组x,y,z( 1 ≤ x < y < z ≤ n 1\le x<y<z\le n 1x<y<zn),用 a y − a z a_y-a_z ayaz替换 a x a_x ax,输出操作的次数和每次的操作。
思路:首先如果原数组就是非递减数组,那么就不需要再进行操作了。
如果原数组不是非递减数组,必须保证a[n]>0,因为如果a[n]<0,那么整个数组都必须是小于零的数,如果存在a[x]>a[y],那么就找不到一个数可以使a[y]-a[z]<a[y],因为a[z]<0,如果a[n-1]>a[n]那么也不存在z>n使得a[n]-a[z]<a[n];
后面只需要从a[n]开始倒序遍历,只要遇到a[i]>a[i+1]就执行a[i]=a[i+1]-a[n]操作即可。

#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
const int N=2e5+5;
ll a[N];
void solve()
{
    int n;
    scanf("%d",&n);
    bool flag=false;
    for(int i = 1;i <= n;i++)
    {
        scanf("%lld",a+i);
        if(i>1&&a[i]<a[i-1])
        {
            flag=true;
        }
    }
    int cnt=0;
    vector<int> ans;
    ans.clear();
    if(flag)
    {
        if(a[n]<0||a[n-1]>a[n])
        {
            printf("-1\n");
        }
        else{
            for(int i = n-2;i >= 1;i--)
            {
                if(a[i]>a[i+1])
                {
                    a[i]=a[i+1]-a[n];
                    cnt++;
                    ans.push_back(i);
                }
            }
            printf("%d\n",cnt);
            for(int i = 0;i < cnt;i++)
            {
                printf("%d %d %d\n",ans[i],ans[i]+1,n);
            }
        }
    }
    else{
        printf("0\n");
    }
}

int main()
{
//	freopen("in.txt","r",stdin);
	int t = 1;
	scanf("%d",&t);
	while(t--)
	{
		solve();
	}
    return 0;
}

D Infinite Set 思维+DP

题目大意:给一个长度为n的数组a。
有一个无限大的集合S,包含所有满足以下条件之一的x:
1.x=a[i]对于 1 ≤ i ≤ n 1 \le i\le n 1in
2.x=2y+1 y是S集合里的数字.
3.x=4y y是S集合里的数字
输出S集合中严格小于 2 p 2^p 2p的数的个数,结果对1e9+7取余.
思路:看到题目中2,4还有最后的结果 2 p 2^p 2p,应该想到从2进制的角度考虑(本蒟蒻没有想到)
我们用dp[i]表示大于等于 2 i 2^i 2i,小于 2 i + 1 2^{i+1} 2i+1的数的个数,也就是数的2进制位数为i的个数。
那么对于dp[i]我们可以用dp[i-1]一步生成也可以用dp[i-2]一步生成,那么递推式如下
d p [ i ] = d p [ i − 1 ] + d p [ i − 2 ] dp[i]=dp[i-1]+dp[i-2] dp[i]=dp[i1]+dp[i2]
我们还需要对a数组进行去重处理,如果a[i]能生成a[j]的话,那么就不需要再统计a[j]所生成的数字的个数了。

#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
const int N=2e5+5,maxn=1e9,mod=1e9+7;
int a[N];
int dp[N];
map<int,bool> mp;
ll sum[N];
bool judge(ll x)
{
    while(x>0)
    {
        if(x%2)
        {
            x/=2;
        }
        else if(x%4==0)
        {
            x/=4;
        }
        else{
            break;
        }
        if(mp.count(x))
        {
            return false;
        }
    }
    return true;
}
void solve()
{
    int n,p;
    scanf("%d%d",&n,&p);
    for(int i =1;i <= n;i++)
    {
        scanf("%d",a+i);
        mp[a[i]]=true;
    }
    for(int i = 1;i <= n;i++)
    {
        if(judge(a[i]))
        {
            int p = log2(a[i]);
            dp[p]++;
        }
    }
    dp[1]=(dp[0]+dp[1])%mod;
    sum[0]=dp[0];
    sum[1]=(sum[0]+dp[1])%mod;
    for(int i = 2;i<=p;i++)
    {
        dp[i]=(dp[i-1]+dp[i-2]+dp[i])%mod;
        sum[i]=(dp[i]+sum[i-1])%mod;
    }

    cout << sum[p-1] << endl;
}
int main()
{
//	freopen("in.txt","r",stdin);
	int t = 1;
//	scanf("%d",&t);
	while(t--)
	{
		solve();
	}
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值