Educational Codeforces Round 75 (Rated for Div. 2)

A. Broken Keyboard (CF 1251 A)

题目大意

键盘按键,鬼畜点一按会出现两次。现给出按键结果,判断哪些键一定不鬼畜。

解题思路

看同个字母连续出现奇数次还是偶数次即可。


神奇的代码

#include 
#define MIN(a,b) ((((a)<(b)?(a):(b))))
#define MAX(a,b) ((((a)>(b)?(a):(b))))
#define ABS(a) ((((a)>0?(a):-(a))))
using namespace std;
typedef long long LL;
typedef vector VI;
typedef pair PII;
typedef vector VPII;
typedef vector VL;
typedef pair PLL;
typedef vector VPLL;

template 
void read(T &x) {
    int s = 0, c = getchar();
    x = 0;
    while (isspace(c)) c = getchar();
    if (c == 45) s = 1, c = getchar();
    while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    if (s) x = -x;
}

template 
void write(T x, char c = ' ') {
    int b[40], l = 0;
    if (x < 0) putchar(45), x = -x;
    while (x > 0) b[l++] = x % 10, x /= 10;
    if (!l) putchar(48);
    while (l) putchar(b[--l] | 48);
    putchar(c);
}

int main(void) {
    int kase; read(kase);
    for (int i = 1; i <= kase; i++) {
        char s[508];
        scanf("%s",s);
        set qwq;
        int len=strlen(s);
        for(int i=0;i



B. Binary Palindromes (CF 1251 B)

题目大意

给了\(n\)\(01\)串,可以任意交换任意对串中任意的数字任意多次,问最多能弄出多少个回文串。

解题思路

我们发现\(01\)串长度是奇数的话一定可以自身交换成回文串,而如果是偶数的话,如果是偶数个\(1\)\(0\)也可以自身交换成回文串,如果是奇数个\(0\)\(1\)则不行,记这种串为\(s\)。由于奇数长度的串可以与\(s\)串进行交换使得\(s\)变成回文串。故如果有奇数串则全部都可以变成回文串,如果没有奇数串,但有偶数个\(s\)串,它们俩俩交换也可以是其都变成回文串,故有偶数个\(s\)串则全部都可以变成回文串,有奇数个的话就只有一个不能变成回文串。


神奇的代码

#include 
#define MIN(a,b) ((((a)<(b)?(a):(b))))
#define MAX(a,b) ((((a)>(b)?(a):(b))))
#define ABS(a) ((((a)>0?(a):-(a))))
using namespace std;
typedef long long LL;
typedef vector VI;
typedef pair PII;
typedef vector VPII;
typedef vector VL;
typedef pair PLL;
typedef vector VPLL;

template 
void read(T &x) {
    int s = 0, c = getchar();
    x = 0;
    while (isspace(c)) c = getchar();
    if (c == 45) s = 1, c = getchar();
    while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    if (s) x = -x;
}

template 
void write(T x, char c = ' ') {
    int b[40], l = 0;
    if (x < 0) putchar(45), x = -x;
    while (x > 0) b[l++] = x % 10, x /= 10;
    if (!l) putchar(48);
    while (l) putchar(b[--l] | 48);
    putchar(c);
}

int main(void) {
    int kase; read(kase);
    for (int ii = 1; ii <= kase; ii++) {
        int n;
        read(n);
        int cnt[2]={0};
        int aa=0;
        for(int i=0;i



C. Minimize The Integer (CF 1251 C)

题目大意

给了一串数字,相邻奇偶性不同的可以交换位置,问最小能交换出的数字是多少。

解题思路

奇偶性相同的数字不能交换,那么它们的相对位置不能发现变化,而不同的可以随便变。那么我们把奇数的单独拎出来,偶数的单独拎出来,两个指针分别指着奇数组和偶数组,然后每次取奇偶中最小的放回即可。


神奇的代码

#include 
#define MIN(a,b) ((((a)<(b)?(a):(b))))
#define MAX(a,b) ((((a)>(b)?(a):(b))))
#define ABS(a) ((((a)>0?(a):-(a))))
using namespace std;
typedef long long LL;
typedef vector VI;
typedef pair PII;
typedef vector VPII;
typedef vector VL;
typedef pair PLL;
typedef vector VPLL;

template 
void read(T &x) {
    int s = 0, c = getchar();
    x = 0;
    while (isspace(c)) c = getchar();
    if (c == 45) s = 1, c = getchar();
    while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    if (s) x = -x;
}

template 
void write(T x, char c = ' ') {
    int b[40], l = 0;
    if (x < 0) putchar(45), x = -x;
    while (x > 0) b[l++] = x % 10, x /= 10;
    if (!l) putchar(48);
    while (l) putchar(b[--l] | 48);
    putchar(c);
}

int main(void) {
    int kase; read(kase);
    for (int i = 1; i <= kase; i++) {
        char s[400005];
        scanf("%s",s);
        int len=strlen(s);
        vector cnt[2];
        for(int i=0;i



D. Salary Changing (CF 1251 D)

题目大意

\(n\)个人发工资,每人有一个发工资的钱数的范围,要求确定一种发工资方案,使得所有人所得的工资的中位数最大,且发的工资总数不超过\(s\)

解题思路

很容易想到可以二分中位数\(mid\),然后对于工资范围\([l_i,r_i]\),如果\(r_i,这种人肯定给\(l_i\),而对于\(l_i\geq mid\),这种人也肯定发\(l_i\),至于\(l_i,我们需要中位数为\(mid\),就要有\(m=\frac{n+1}{2}\)个人的工资大于等于\(mid\),如果此时这种人数小于\(m\)的话,还差\(cnt\)个,我们给\(l_i\)最大的\(cnt\)个人发\(mid\)工资,剩下的都发\(l_i\)即可。如果大于则全部发\(l_i\),然后\(mid\)增大继续找。


神奇的代码

#include 
#define MIN(a,b) ((((a)<(b)?(a):(b))))
#define MAX(a,b) ((((a)>(b)?(a):(b))))
#define ABS(a) ((((a)>0?(a):-(a))))
using namespace std;
typedef long long LL;
typedef vector VI;
typedef pair PII;
typedef vector VPII;
typedef vector VL;
typedef pair PLL;
typedef vector VPLL;

template 
void read(T &x) {
    int s = 0, c = getchar();
    x = 0;
    while (isspace(c)) c = getchar();
    if (c == 45) s = 1, c = getchar();
    while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    if (s) x = -x;
}

template 
void write(T x, char c = ' ') {
    int b[40], l = 0;
    if (x < 0) putchar(45), x = -x;
    while (x > 0) b[l++] = x % 10, x /= 10;
    if (!l) putchar(48);
    while (l) putchar(b[--l] | 48);
    putchar(c);
}

bool check(LL mid,vector> sol,int n,LL s){
    int cnt=0;
    vector qwq;
    for(auto i:sol){
        if (i.second=mid) ++cnt,s-=i.first;
        else qwq.push_back(i.first);
    }
    int m=(n+1)>>1;
    if (cnt>m) return 1;
    if (s<0) return 0;
    if (qwq.size()+cnt> sol;
        for(int i=1;i<=n;++i){
            LL l,r;
            read(l);
            read(r);
            sol.push_back(make_pair(l,r));
        }
        LL l=0,r=1e9+7;
        LL ans=0;
        while(l>1;
            if (check(mid,sol,n,s)) ans=mid,l=mid+1;
            else r=mid;
        }
        write(ans,'\n');
    }
    return 0;
}



E1 E2. Voting (Easy/Hard Version) (CF 1251 E1 E2)

题目大意

拉选票,有\(n\)个人,第\(i\)个人需要用\(p_i\)金钱贿赂才会给你投票,或者看见有大于等于\(m_i\)个人给你投票的话他也会给你投票。现在你需要所有人都给你投票,问最小需要多少钱。

解题思路

分别考虑枚举金钱,贿赂多少人后无果。但考虑到知道多少人给你投票的角度的话似乎可解,于是我们将人通过\(m_i\)分组,对\(m_i\)倒序枚举,对于每组来说有一个\(cur=m_i\),此时\(m_j的人都已经投票给你了,记为\(sum[i-1]\),再加上自己已经贿赂了\(py\)个人,如果\(sum[i-1]+py\geq cur\)的,那这组人就归降于您,否则就需要再在\(m_j\geq cur\)的人中贿赂直到\(sum[i-1]+py=cur\)或都贿赂完,我们自然是贪心的找\(p_i\)最小的那些人贿赂,用优先队列维护即可。


神奇的代码

#include 
#define MIN(a,b) ((((a)<(b)?(a):(b))))
#define MAX(a,b) ((((a)>(b)?(a):(b))))
#define ABS(a) ((((a)>0?(a):-(a))))
using namespace std;
typedef long long LL;
typedef vector VI;
typedef pair PII;
typedef vector VPII;
typedef vector VL;
typedef pair PLL;
typedef vector VPLL;

template 
void read(T &x) {
    int s = 0, c = getchar();
    x = 0;
    while (isspace(c)) c = getchar();
    if (c == 45) s = 1, c = getchar();
    while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    if (s) x = -x;
}

template 
void write(T x, char c = ' ') {
    int b[40], l = 0;
    if (x < 0) putchar(45), x = -x;
    while (x > 0) b[l++] = x % 10, x /= 10;
    if (!l) putchar(48);
    while (l) putchar(b[--l] | 48);
    putchar(c);
}

int main(void) {
    int kase; read(kase);
    for (int i = 1; i <= kase; i++) {
        int n;
        read(n);
        int cnt[n+1]={0};
        vector money[n+1];
        for(int p,m,i=1;i<=n;++i){
            read(m);
            read(p);
            cnt[m]++;
            money[m].push_back(p);
        }
        priority_queue,greater> qwq;
        LL ans=0;
        int by=0;
        for(int i=1;i<=n;++i) cnt[i]+=cnt[i-1];
        for(int i=n-1;i>0;--i){
            if (money[i].empty()) continue;
            for(int j:money[i]) qwq.push(j);
            if (cnt[i-1]+by>=i) continue;
            while(!qwq.empty()&&cnt[i-1]+by



F. Red-White Fence (CF 1251 F)

题目大意

\(n\)块白栅栏\(k\)块红栅栏有各自高度,要求选出一个红栅栏和若干个白栅栏,排成一排,要求红栅栏高度最高,红栅栏左边的白栅栏(可以没有)高度严格递增,右边的白栅栏(可以没有)高度严格递减,且它们的周长为\(Q\),有\(q\)次周长询问,分别回答方案数。

解题思路

记红栅栏高度为\(h\),选了\(cnt\)个白栅栏,这栅栏的周长为\(4\times h\times (cnt+1)\)
由于要严格递增或递减,对于长度相同有若干个的白栅栏只会用到两个,于是白栅栏就分成两种类型,一种是高度出现一次的,另一种是出现两次(及以上都归为两次)的。设红栅栏高度为\(h\),则高度小于\(h\)的白栅栏中,高度出现一次的有\(cnt_1\)个,出现两次的有\(cnt_2\)个,要选\(w\)个白栅栏。然后我们考虑方案数。
如果\(cnt_2\)为零,方案数即为\(C^{w}_{cnt_1}\times \sum\limits_{i=0}^{w}C^{i}_{w}=C^{w}_{cnt_1}\times 2^{w}\),但如果不为\(0\),对于这些数我们要考虑选\(1\)个还是选\(2\)个,选\(1\)个还要考虑放左边还是放右边。我们可以这样处理,把这\(cnt_2\)个出现两次的这些数的个数翻倍,一个表示把它放左边的,一个表示把它放右边的,那么对于这个数就有三种选择的情况,分别对应上面的三种。所以最终的方案数即为\(\sum\limits_{i=0}^{w}2^{i}\times C^{i}_{cnt_1}\times C^{w-i}_{cnt_2}\),这是个卷积形式,我们对于每一个红栅栏,构造多项式\(f(x)=\sum\limits_{i}2^{i}\times C^{i}_{cnt_1}x^{i}\)\(g(x)=\sum\limits_{i}C^{i}_{cnt_2}x^{i}\),用\(NTT\)加速\(f*g\),则这个红栅栏对答案的贡献为\(x^{w}\)的系数。预处理答案后\(O(1)\)回答。总时间复杂度为\(O(k*n\log_2 n+q)\)
随便找了个NTT模板


神奇的代码

#include 
#define MIN(a,b) ((((a)<(b)?(a):(b))))
#define MAX(a,b) ((((a)>(b)?(a):(b))))
#define ABS(a) ((((a)>0?(a):-(a))))
using namespace std;
typedef long long LL;
typedef vector VI;
typedef pair PII;
typedef vector VPII;
typedef vector VL;
typedef pair PLL;
typedef vector VPLL;

template 
void read(T &x) {
    int s = 0, c = getchar();
    x = 0;
    while (isspace(c)) c = getchar();
    if (c == 45) s = 1, c = getchar();
    while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
    if (s) x = -x;
}

template 
void write(T x, char c = ' ') {
    int b[40], l = 0;
    if (x < 0) putchar(45), x = -x;
    while (x > 0) b[l++] = x % 10, x /= 10;
    if (!l) putchar(48);
    while (l) putchar(b[--l] | 48);
    putchar(c);
}

const LL mod=998244353;

const int maxn=3e5+8;

int N,M,n,k,q,wi,bl;

LL a[maxn*3],b[maxn*3],c[maxn*3],g,jie[maxn],jieinv[maxn],white[maxn],red[6],ans[5*maxn];

int cnt_white[maxn],cnt_black[maxn];

LL qpower(LL x, LL y){
    LL res=1;
    while (y){
        if (y&1) (res*=x)%=mod;
        (x*=x)%=mod;
        y>>=1;
    }
    return res;
}

LL inv(LL x){return qpower(x, mod - 2);}

void NTT(LL *arr,int size,int type){
    int rev[maxn*3];
    rev[0]=0;
    for(int i=1;i>1]>>1)|((i&1)?(size>>1):0);
    for(int i=0;ii) swap(arr[i],arr[rev[i]]);
    for(int len=2;len<=size;len<<=1){
        LL wn=qpower(g,(mod-1)/len);
        if(type==-1) wn=inv(wn);
        for(int i=0;i>1);++j,w=w*wn%mod){
                LL tmp1=arr[i+j],tmp2=arr[i+(len>>1)+j]*w%mod;
                arr[i+j]=tmp1+tmp2;
                arr[i+j+(len>>1)]=tmp1-tmp2;
                if(arr[i+j]>=mod) arr[i+j]-=mod;
                if(arr[i+j+(len>>1)]<0) arr[i+j+(len>>1)]+=mod;
            }
        }
    }
    if(type==-1) {
        LL t=inv(size);
        for(int i=0;in) return 0;
    if (m<0||n<0) return 0;
    return jie[n]*jieinv[m]%mod*jieinv[n-m]%mod;
}

int main(void) {
    read(n);
    read(k);
    for(int u,i=1;i<=n;++i){
        read(u);
        if (cnt_white[u]<2) white[++wi]=u,++cnt_white[u];
    }
    for(int u,i=1;i<=k;++i){
        read(u);
        if (cnt_black[u]==0) red[++bl]=u,++cnt_black[u];
    }
    sort(white+1,white+1+wi);
    sort(red+1,red+1+bl);
    jie[0]=jie[1]=jieinv[1]=jieinv[0]=1;
    for(int i=2;i<=n;++i){
        jie[i]=jie[i-1]*i%mod;
        jieinv[i]=inv(jie[i]);
    }
    for(int i=1;i<=bl;++i){
        int pos=lower_bound(white+1,white+1+wi,red[i])-white;
        N=M=0;
        for(int j=1;j



你可能感兴趣的:(Educational Codeforces Round 75 (Rated for Div. 2))