Codeforces Round #672 (Div. 2)

原题链接

题外话

恢复性训练

A

题意

问你一组数列排成非递减的数列, 是否在$ n * (n-1)/2-1 $次数中完成

思路

妈妈的, 我把自己演了,写了个假代码
直接判断这个数组是否是单调递减的,是的话输出no ,否则输出yes ,至于为什么,可以画个图理解一下(很简单的图,我就不管了)

代码

#include <cstdio>
#include <algorithm>
#include<iomanip>
#include <iostream>
#include <cmath>
#include <string>
#include <vector>
#include <set>
#include <queue>
#include <cstring>
#include<stack>
#include <cassert>
#include<map>
#define cl(x) memset(x,0,sizeof(x))
#define rep(i,a,b) for(i=a;i<=b;i++)
#define drep(i,a,b) for(i=a;i>=b;i--)
#define em(x) emplace(x)
#define emb(x) emplace_back(x)
#define emf(x) emplace_front(x)
#define fi first
#define se second
#define pb push_back
#define de(x) cerr<<#x<<" = "<<x<<endl
#define __i __int128
#define pn printf("
");
#define pk printf(" ");
#define p(n) printf("%d",n);
#define pln(n) printf("%d
",n);
#define s(n) scanf("%d",&n);
#define ss(n) scanf("%s",n);
#define ps(n) printf("%s",n);
#define sld(n) scanf("%lld",&n);
#define pld(n) printf("%lld",n);
#define slf(n) scanf("%lf",&n);
#define plf(n) printf("%lf",n);
#define sc(n) scanf("%c",&n);
#define pc(n) printf("%c",n);
#define dbg(x...) do { cout << "33[32;1m" << #x << " -> "; err(x); } while (0)

using namespace std;
//using namespace __gnu_pbds;
typedef long long LL;
typedef pair<int,int> pii;
typedef pair<LL,LL> pLL;
const int inf=0x7fffffff;
const int N =3.1e5;
const int maxn = 200010;

void clear(unsigned char *pta, int size )
{//结构体初始化
    while(size>0)
    {
        *pta++ = 0;
        size --;
    }
}

LL   n, k, m ;
LL ar[N],br[N],cr[200005],dr[200005];
LL i,j,g;
LL MOD = 998244353 ;


LL fac[N],inv_fac[N];

//快速幂
LL qpow(LL x, LL y ){
    x%=MOD;
    long long res=1%MOD;
    while(y){
        if(y&1)res=res*x%MOD;
        y>>=1;
        x=x*x%MOD;
    }
    return res;

}

void pre(){
    fac[0] =1 ;
    for(int i=1;i<N;i++){
        fac[i] =fac[i-1] * i %MOD;
    }
    inv_fac[N - 1 ] = qpow(fac[N - 1] , MOD-2 ) ;

    for(int i =N-2 ;i>=0 ;i--){
        inv_fac[i] = inv_fac[i+1] * (i+1) %MOD;
    }

}

LL C (LL a ,LL b){
    if(a<0 || b> a )//因为是C(a,b) 所以b《= a
    {
        return 0;
    }

    return fac[a] * inv_fac[b] % MOD *inv_fac[a-b]%MOD;//a 的阶乘 / ( b的阶乘 * (a-b的阶乘))

}
void answer(){
   sld(n);LL cnt =0 ;
   for(int i=1;i<=n;i++)sld(ar[i]);
   for(int i=1;i<=n;i++){
        if(ar[i]>ar[i+1] && i+1<=n ){
            cnt ++ ;
        }
   }
   if(cnt == n-1 )printf("NO
");
   else printf("YES
");

 }


int main()
{
//    ios::sync_with_stdio(0);
//    cin.tie(0), cout.tie(0);
//       pre();
    int t;s(t);
    while(t--)
        answer();


    return 0;

}


B

题意

给你一串数, 然后让你找出来 两个数的& 大于等于 两个数的xor 的数量

思路

一看有xor 和 & 一定要想到 二进制 , 然后通过二进制下的数字,发现 & 的 >= xor 只能是当 两个数字的最大位置的 1 位置相同才行。
所以存一下每个数的 最大位置上的 1 的位置 ,然后求和即可

代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <math.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <string>
#include <sstream>
#include <iostream>
#include <time.h>
#include <queue>
#include <list>
#include <map>
#include <set>
#include <vector>
#include <stack>
#include <string.h>
#include <bitset>
#define sf scanf
#define pf printf
#define lf double
#define p123 printf("123
");
#define pn printf("
");
#define pk printf(" ");
#define p(n) printf("%d",n);
#define pln(n) printf("%d
",n);
#define s(n) scanf("%d",&n);
#define ss(n) scanf("%s",n);
#define ps(n) printf("%s",n);
#define sld(n) scanf("%lld",&n);
#define pld(n) printf("%lld",n);
#define slf(n) scanf("%lf",&n);
#define plf(n) printf("%lf",n);
#define sc(n) scanf("%c",&n);
#define pc(n) printf("%c",n);
//#define gc getchar();
#define ll long long
#define re(n,a) memset(n,a,sizeof(n));
#define len(a) strlen(a)
#define eps 1e-13
#define zero(x) (((x) > 0? (x):(-x)) < eps)
using namespace std;


int a[100050];
int b[1000];
#include <stdio.h>
int main(){
    int T;
    s(T)
    while(T --){
        int n;
        s(n)
        re(b,0);
        for(int i = 0; i < n; i ++){
            s(a[i])
            int flag = 0;
            while(a[i] != 0){
                a[i] >>= 1;
                flag ++;
            }
            b[flag] ++;
        }
        ll sum = 0ll;
        for(int i = 0; i < 50; i ++){
            ll temp = b[i];
            sum += (temp*(temp-1ll))>>1;
        }
        pld(sum) pn
    }
    return 0;
}

C1

题意

简单版本的就是给你一组数,然后让你找出来这样一个序列 ($ a_1-a_2+a_3-a_4+... +a_n $ )使得 这个结果是最大的情况

思路

因为是个简单版本的,可以直接暴力求局部最大和最小, 然后相加一下就行

代码

#include <cstdio>
#include <cstdio>
#include <algorithm>
#include<iomanip>
#include <iostream>
#include <cmath>
#include <string>
#include <vector>
#include <set>
#include <queue>
#include <cstring>
#include<stack>
#include <cassert>
#include<map>
#define cl(x) memset(x,0,sizeof(x))
#define rep(i,a,b) for(i=a;i<=b;i++)
#define drep(i,a,b) for(i=a;i>=b;i--)
#define em(x) emplace(x)
#define emb(x) emplace_back(x)
#define emf(x) emplace_front(x)
#define fi first
#define se second
#define pb push_back
#define de(x) cerr<<#x<<" = "<<x<<endl
#define __i __int128
#define pn printf("
");
#define pk printf(" ");
#define p(n) printf("%d",n);
#define pln(n) printf("%d
",n);
#define s(n) scanf("%d",&n);
#define ss(n) scanf("%s",n);
#define ps(n) printf("%s",n);
#define sld(n) scanf("%lld",&n);
#define pld(n) printf("%lld",n);
#define slf(n) scanf("%lf",&n);
#define plf(n) printf("%lf",n);
#define sc(n) scanf("%c",&n);
#define pc(n) printf("%c",n);
#define dbg(x...) do { cout << "33[32;1m" << #x << " -> "; err(x); } while (0)

using namespace std;
//using namespace __gnu_pbds;
typedef long long LL;
typedef pair<int,int> pii;
typedef pair<LL,LL> pLL;
const int inf=0x7fffffff;
const int N =3.1e5;
const int maxn = 200010;

void clear(unsigned char *pta, int size )
{//结构体初始化
    while(size>0)
    {
        *pta++ = 0;
        size --;
    }
}

LL   n, k, m ;
LL ar[N],br[N],cr[200005],dr[200005];
LL i,j,g;
LL MOD = 998244353 ;


LL fac[N],inv_fac[N];

//快速幂
LL qpow(LL x, LL y ){
    x%=MOD;
    long long res=1%MOD;
    while(y){
        if(y&1)res=res*x%MOD;
        y>>=1;
        x=x*x%MOD;
    }
    return res;

}

void pre(){
    fac[0] =1 ;
    for(int i=1;i<N;i++){
        fac[i] =fac[i-1] * i %MOD;
    }
    inv_fac[N - 1 ] = qpow(fac[N - 1] , MOD-2 ) ;

    for(int i =N-2 ;i>=0 ;i--){
        inv_fac[i] = inv_fac[i+1] * (i+1) %MOD;
    }

}

LL C (LL a ,LL b){
    if(a<0 || b> a )//因为是C(a,b) 所以b《= a
    {
        return 0;
    }

    return fac[a] * inv_fac[b] % MOD *inv_fac[a-b]%MOD;//a 的阶乘 / ( b的阶乘 * (a-b的阶乘))

}
void answer(){
    sld(n) ;sld(k);
    for(int i=1 ;i<=n;i++)sld(ar[i]);
    ar[0] = ar[n+1 ] =0 ;LL sum =0 ;
    for(int i=1 ;i<=n;i++){
        if(ar[i]>ar[i-1]&&ar[i] >ar[i+1 ])sum +=ar[i];
        if(ar[i]<ar[i-1]&&ar[i] <ar[i+1 ])sum -=ar[i];
    }
    pld(sum);pn;
 }


int main()
{
//    ios::sync_with_stdio(0);
//    cin.tie(0), cout.tie(0);
//       pre();
    int t;s(t);
    while(t--)
        answer();


    return 0;

}

C2

题意

这个版本在前面的基础上添加了一个q的移动, 每次都是把两个ar[r] , ar[l] 进行交换位置, 问你交换完之后的结果

思路

这个其实要考虑的事情也不多, 因为他是两个数进行交换,

  • 那么假设ar[l] < ar[r] ,那么可能ar[r] 交换之后也是局部最大的,
  • 那么假设ar[l] > ar[r] ,那么可能ar[r] 交换之后也是局部最小的,
  • 所以受这个交换的影响的数, 一共只有ar[l] 和 ar[r] 这两个和他们左右两边的数,
  • 所以,只需要每次先把这两个数和他们左右两边的数先判断一下,是否有局部最大的数或者最小的数, 有的话就从结果中先去掉
  • 之后,在交换完之后, 在进行判断在新位置上的ar[l] , ar[r] 是否是局部最大的数或者最小的数, 是的话再加进来即可

代码

#include <cstdio>
#include <algorithm>
#include<iomanip>
#include <iostream>
#include <cmath>
#include <string>
#include <vector>
#include <set>
#include <queue>
#include <cstring>
#include<stack>
#include <cassert>
#include<map>
#define cl(x) memset(x,0,sizeof(x))
#define rep(i,a,b) for(i=a;i<=b;i++)
#define drep(i,a,b) for(i=a;i>=b;i--)
#define em(x) emplace(x)
#define emb(x) emplace_back(x)
#define emf(x) emplace_front(x)
#define fi first
#define se second
#define pb push_back
#define de(x) cerr<<#x<<" = "<<x<<endl
#define __i __int128
#define pn printf("
");
#define pk printf(" ");
#define p(n) printf("%d",n);
#define pln(n) printf("%d
",n);
#define s(n) scanf("%d",&n);
#define ss(n) scanf("%s",n);
#define ps(n) printf("%s",n);
#define sld(n) scanf("%lld",&n);
#define pld(n) printf("%lld",n);
#define slf(n) scanf("%lf",&n);
#define plf(n) printf("%lf",n);
#define sc(n) scanf("%c",&n);
#define pc(n) printf("%c",n);
#define dbg(x...) do { cout << "33[32;1m" << #x << " -> "; err(x); } while (0)

using namespace std;
//using namespace __gnu_pbds;
typedef long long LL;
typedef pair<int,int> pii;
typedef pair<LL,LL> pLL;
const int inf=0x7fffffff;
const int N =5e5+10;
const int maxn = 200010;

void clear(unsigned char *pta, int size )
{//结构体初始化
    while(size>0)
    {
        *pta++ = 0;
        size --;
    }
}

LL   n, k, m ;
LL ar[N],br[N],cr[200005],dr[200005];
LL i,j,g;

set<int > big_pos , small_pos;
LL sum;
bool big(int i){
    return ar[i] >  max(ar[i-1],ar[i+1]);
}
bool small(int i){
    return ar[i] < min(ar[i-1] , ar[i+1]);

}


void clear_pos(int pos){
//    cout<<ar[pos]<<endl;
    if(big(pos)&&big_pos.count(pos)){

        sum -= ar[pos];
        big_pos.erase(pos);
    }
    if(small(pos)&&small_pos.count(pos)){

        sum+=ar[pos];
        small_pos.erase(pos);
    }
//    cout<<sum<<endl;

}
void updata(int pos){

    if(big(pos)&&!big_pos.count(pos)){

        sum += ar[pos];
        big_pos.insert(pos);
    }
    if(small(pos)&&!small_pos.count(pos)){
        sum-=ar[pos];
        small_pos.insert(pos);
    }
//    cout<<i<<" "<<sum<<endl;


}
void answer(){
    sld(n);sld(k);
    for(int i=1;i<=n;i++)sld(ar[i]);
    sum =0;
    ar[n+1] = 0;
    big_pos.clear();
    small_pos.clear();
    for(int i=1;i<=n;i++){
        updata(i);
    }
    pld(sum);pn;
    for(int i=k;i>=1;i--){
        int x,y ;s(x);s(y);
        clear_pos(x-1);        clear_pos(x);        clear_pos(x+1);
        clear_pos(y-1);        clear_pos(y);        clear_pos(y+1);
        swap(ar[x],ar[y]);
        updata(x-1);        updata(x);        updata(x+1);
        updata(y-1);updata(y);updata(y+1);
        pld(sum);pn;

    }

    }


int main()
{
//    ios::sync_with_stdio(0);
//    cin.tie(0), cout.tie(0);

    int t;s(t);
    while(t--)answer();


    return 0;

}


D

题意

一共n个灯,然后每个灯有自己亮的时间l,r 然后问你是否有k个灯能同时亮着,有的话,求出一共可以选择出来的数量,没有就是0

思路

其实就是一个贪心 + 组合数学

  • 首先找出同一时间亮着的灯 (这里需要自己想一个操作, 我是跟一个带佬学的用vector的pair ,设置 l 为 -1 ,r 为 1 , 之后判断second 是- 1 的)
  • 然后 通过组合数 来求出这个时间的数量,
  • 进行求和即可

代码


#include <cstdio>
#include <algorithm>
#include<iomanip>
#include <iostream>
#include <cmath>
#include <string>
#include <vector>
#include <set>
#include <queue>
#include <cstring>
#include<stack>
#include <cassert>
#include<map>
#define cl(x) memset(x,0,sizeof(x))
#define rep(i,a,b) for(i=a;i<=b;i++)
#define drep(i,a,b) for(i=a;i>=b;i--)
#define em(x) emplace(x)
#define emb(x) emplace_back(x)
#define emf(x) emplace_front(x)
#define fi first
#define se second
#define pb push_back
#define de(x) cerr<<#x<<" = "<<x<<endl
#define __i __int128
#define pn printf("
");
#define pk printf(" ");
#define p(n) printf("%d",n);
#define pln(n) printf("%d
",n);
#define s(n) scanf("%d",&n);
#define ss(n) scanf("%s",n);
#define ps(n) printf("%s",n);
#define sld(n) scanf("%lld",&n);
#define pld(n) printf("%lld",n);
#define slf(n) scanf("%lf",&n);
#define plf(n) printf("%lf",n);
#define sc(n) scanf("%c",&n);
#define pc(n) printf("%c",n);
#define dbg(x...) do { cout << "33[32;1m" << #x << " -> "; err(x); } while (0)

using namespace std;
//using namespace __gnu_pbds;
typedef long long LL;
typedef pair<int,int> pii;
typedef pair<LL,LL> pLL;
const int inf=0x7fffffff;
const int N =3.1e5;
const int maxn = 200010;

void clear(unsigned char *pta, int size )
{//�ṹ���ʼ��
    while(size>0)
    {
        *pta++ = 0;
        size --;
    }
}

LL   n, k, m ;
LL ar[N],br[N],cr[200005],dr[200005];
LL i,j,g;
LL MOD = 998244353 ;


LL fac[N],inv_fac[N];

//������
LL qpow(LL x, LL y ){
    x%=MOD;
    long long res=1%MOD;
    while(y){
        if(y&1)res=res*x%MOD;
        y>>=1;
        x=x*x%MOD;
    }
    return res;

}

void pre(){
    fac[0] =1 ;
    for(int i=1;i<N;i++){
        fac[i] =fac[i-1] * i %MOD;
    }
    inv_fac[N - 1 ] = qpow(fac[N - 1] , MOD-2 ) ;

    for(int i =N-2 ;i>=0 ;i--){
        inv_fac[i] = inv_fac[i+1] * (i+1) %MOD;
    }

}

LL C (LL a ,LL b){
    if(a<0 || b> a )//����C��a��b�� ����b��= a
    {
        return 0;
    }

    return fac[a] * inv_fac[b] % MOD *inv_fac[a-b]%MOD;//a �Ľ׳� / �� b�Ľ׳� * ��a-b�Ľ׳ˣ���

}
void answer(){
   sld(n);sld(k);
   vector<pii  >v;
   for(int i=1 ;i<=n;i++){
        int l, r ;s(l);s(r);
        v.pb({l,-1});v.pb({r,1});
   }
   sort(v.begin(), v.end());
   LL sum =0  , cnt =0 ;
   for(int i=0;i<v.size();i++){
    sum -= v[i].se;
    if(v[i].se==-1){
        cnt = (cnt + C(sum - 1  , k -1  ))%MOD;

//        cout<<cnt<<" ,"<<sum<<endl;
    }
//    cout<<sum<<endl ;
   }
   pld(cnt);pn;
 }


int main()
{
//    ios::sync_with_stdio(0);
//    cin.tie(0), cout.tie(0);
       pre();
//    int t;s(t);
//    while(t--)
        answer();


    return 0;

}

原文地址:https://www.cnblogs.com/gaohaoy/p/13733304.html