2022.4.25~2022.4.27的CF题目总结 (标签: constructive algorithms 难度: 1300~1500)

 

 

 

2022.9.10 打卡一遍~ (之前好像也复盘过一遍)

4.26


 D. Productive Meeting

Problem - 1579D - Codeforces   难度1400 , 类型:数字成对构造,堆

题意

给出数组a[i] ,表示第i个人可以和别人搭配a[i]次,问最多有几组搭配,并输出搭配的两人分别是谁,不能自己和自己搭配

分析

这题开始真没想到,不能用指针来指着跑,这样容易把最后一个人剩下很多

应该用动态的方法,每次取最大的两个人来搭配,用priority_queue大根堆统计

附录:优先队列

/* 1 */ priority_queue<int> pq1;                         //默认大根堆且默认基础容器为vector
/* 2 */ priority_queue<vector<int>, less<int> > pq2;     //与 1 的性质一模一样
/* 3 */ priority_queue<deque<int>, greater<int> > pq3;   //小根堆且基础容器为deque

 

//CF  782  B

#include <bits/stdc++.h>

using namespace std;

typedef pair<int,int> PII;

typedef long long LL;

const int N = 2e5+10;
const LL mod = 1e9+7;

priority_queue<PII> a;

int main()
{
    int t;
    cin >> t;
    while(t --)
    {
        int n, sum=0, maxx=0;
        cin >> n;
        
        while(a.size())     a.pop();
        PII x;
        for(int i = 1; i <=n; i ++)
        {
            cin>>x.first;
            x.second = i;
            a.push(x);
            sum += x.first;  
            maxx = max(maxx, x.first);
        }
        
        int times = min(sum-maxx, sum/2);
        cout << times << '\n';
        if(times==0)continue;
        
        while(times)
        {
            PII x1 = a.top(); a.pop();
            PII x2 = a.top(); a.pop();
            
            cout << x1.second << ' '<< x2.second <<'\n';
            x1.first --;
            x2.first --;
            if(x1.first) a.push(x1); 
            if(x2.first) a.push(x2);
            times--;
        }
    }    
    return 0;
}

 

 

C. Divan and bitwise operations

Problem - 1614C - Codeforces  难度:1500, 类型:二进制

题意

一序列长度为n,序列未知, 给出m个条件, 分别是l,r,x 意为在区间[l, r], 异或的值为x,求这个序列的所有子序列异或后的值的和

分析

异或看的是二进制每一位如何如何,只有奇数个1和任意个0才能异或出来是1,我们可以把每一位上1的个数(简称num1)和0的个数(简称num2)计算出来, x的所有组合数相加=2x, x的所有奇数组合数相加=2(x-1),所以结果就是 (2num1-1  * 2num2 ) = 2n-1

所以我们只需要知道哪一位有1,然后乘2n-1  即可, 这里采用的是把x都按位或(有1则1)一遍

 

#include <bits/stdc++.h>

using namespace std;

const int N = 2e5+10;
typedef long long LL;
const LL mod = 1e9+7;

LL qmi(LL a, LL b, LL p)
{
    LL now = 1%p;
    while(b)
    {
        if(b&1)    now = now*a%p;
        a = a*a%p;
        b>>=1;
    }
    return now;
}
int main()
{
    int t;
    cin >> t;
    while(t --)
    {
        LL n, m;
        cin >> n >> m;
        
        LL res = 0;
        while(m --)
        {
            LL l, x, r;
            cin >> l >> r >>x;
            res|=x;
        }
        res = res*qmi((LL)2,n-1,1e9+7)%mod;
        cout << res<<endl;
    }
    
    return 0;
}

 

 

 

 

 

 

B. Bit Flipping

Problem - 1659B - Codeforces  难度:1300, 类型:二进制

题意

二进制长度为n, 可以变化k次, 每次变化选择一个数不动,其它数取反,问如何让变化后的二进制最大,输出第一行是变化后的二进制,第二行是每个数不动的次数(用res[]表示)

分析

每个点(i)取反的次数为k-res[i], 二进制从前往后遍历,保证前面的数尽量为1

k为偶数:若第i位为1,则res[i]=0, 若第i位为0,则res[i]=1;

k为偶数:若第i位为0,则res[i]=1, 若第i位为1,则res[i]=0。

最后k如果还有剩余,如果剩余的k为偶数,随便加给某一位都可以,结果不变;反之只能加给最后一个1

 

#include <bits/stdc++.h>

using namespace std;

const int N = 2e5+10;
int res[N];

int main()
{
    int t;
    cin >> t;
    while(t --)
    {
        int n, k;
        string s;
        
        cin >> n >> k;
        cin >> s;
        
        int countk = 0, last = 0;
        for(int i = 0; i< n; i ++)
        {
            if(countk == k)
            {
                res[i] = 0;
                if(k%2==1) s[i] = '1'-s[i]+'0'; 
                continue;
            }
            if(s[i] == '1' && k%2==1)
                res[i] = 1, countk ++, last = i;
            else if(s[i] == '0' && k%2==0)
                res[i] = 1, countk ++, last = i;
            else res[i]=0;
            s[i] = '1';
        }
        for(int i = n-1; i>=0; i--)
        {
            if(s[i]=='1')
            {
                last=max(last, i);
                break;
            }
        }
        
        res[last]+=k-countk;
        if((k-countk)%2==1)    s[last]='0';
        cout << s<<endl;
        for(int i = 0; i < n; i ++)cout << res[i] << ' ';
        cout <<endl;
    }
    
    return 0;
}

 

 



 

4.27

D. Weights Assignment For Tree Edges

Problem - 1611D - Codeforces  难度:1500, 类型:树

题意

n个节点的树, 给出2个数组 bi, pi  。其中bi表示第i个节点的父亲是bi,p数组表示每个点到根节点的距离从小到大的顺序, 即pi表示pi到根节点的距离第i小。需要求出每个点到父节点的距离。

分析

既然给出了每个点到根节点大小顺序,我们就依次给每个点到根节点赋值,只需要满足sum[p[i]]<sum[p[i-1]]

sum[ i ] : i 到根节点的距离     sum[p[i]]=i;

res[ i ] : i 到父节点的距离       res[i]=sum[i]-sum[b[i]];

 

#include <bits/stdc++.h>

using namespace std;

typedef pair<int,int> PII;

typedef long long LL;

const int N = 2e5+10;
const LL mod = 1e9+7;
int n;
int b[N], p[N], sum[N], res[N];

int main()
{
    int t;
    cin >> t;
    while(t --)
    {
        cin >> n;
        for(int i = 1; i <= n; i ++)    cin >> b[i];
        for(int i = 1; i <= n; i ++)    cin >> p[i];
        
        bool f =1;
        for(int i=1;i<=n; i++)
            sum[p[i]] = i;
                   
        for(int i = 1; i <= n; i ++)
            if(b[i] != i && sum[i]-sum[b[i]]<=0)//父节点比自己离根节点远
          f=0; if(b[p[1]]!=p[1] || !f) { puts("-1"); continue; } for(int i = 1; i <= n; i ++) { res[i] = sum[i]-sum[b[i]]; cout << res[i]<< ' '; } cout <<endl; } return 0; }

 

posted @ 2022-04-28 15:29  la-la-wanf  阅读(48)  评论(0编辑  收藏  举报