zoukankan      html  css  js  c++  java
  • Educational Codeforces Round 75 (Rated for Div. 2)

    A. Broken Keyboard (CF 1251 A)

    题目大意

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

    解题思路

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

    神奇的代码
    #include <bits/stdc++.h>
    #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<int> VI;
    typedef pair<int,int> PII;
    typedef vector<PII> VPII;
    typedef vector<LL> VL;
    typedef pair<LL,LL> PLL;
    typedef vector<PLL> VPLL;
    
    template <typename T>
    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 <typename T>
    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<char> qwq;
            int len=strlen(s);
            for(int i=0;i<len;++i){
                if (s[i]==s[i+1]) ++i;
                else qwq.insert(s[i]); 
            }
            for(auto i:qwq) putchar(i);
            puts("");
        }
        return 0;
    }
    


    B. Binary Palindromes (CF 1251 B)

    题目大意

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

    解题思路

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

    神奇的代码
    #include <bits/stdc++.h>
    #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<int> VI;
    typedef pair<int,int> PII;
    typedef vector<PII> VPII;
    typedef vector<LL> VL;
    typedef pair<LL,LL> PLL;
    typedef vector<PLL> VPLL;
    
    template <typename T>
    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 <typename T>
    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<n;++i){
                char s[58];
                scanf("%s",s);
                int len=strlen(s);
                int qwq[2]={0};
                for(int j=0;j<len;++j)
                    ++qwq[s[j]-'0'];
                if (len&1){
                    if (qwq[0]&1) ++cnt[0];
                    else ++cnt[1];
                }
                else if (qwq[0]&1) ++aa;
            }
            aa=aa&1;
            aa=max(aa-cnt[0]-cnt[1],0);
            int ans=n-aa;
            write(ans,'
    ');
        }
        return 0;
    }
    


    C. Minimize The Integer (CF 1251 C)

    题目大意

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

    解题思路

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

    神奇的代码
    #include <bits/stdc++.h>
    #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<int> VI;
    typedef pair<int,int> PII;
    typedef vector<PII> VPII;
    typedef vector<LL> VL;
    typedef pair<LL,LL> PLL;
    typedef vector<PLL> VPLL;
    
    template <typename T>
    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 <typename T>
    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<int> cnt[2];
            for(int i=0;i<len;++i){
                int qwq=s[i]-'0';
                cnt[qwq&1].push_back(qwq);
            }
            auto l=cnt[0].begin();
            auto r=cnt[1].begin();
            while(len--){
                if (l!=cnt[0].end()&&r!=cnt[1].end()){
                    if (*l<*r){
                        putchar(*l+'0');
                        ++l;
                    }
                    else{
                        putchar(*r+'0');
                        ++r;
                    }
                }else if (l!=cnt[0].end()){
                    putchar(*l+'0');
                    l++;
                }else{
                    putchar(*r+'0');
                    ++r;
                }
            }
            puts("");
        }
        return 0;
    }
    


    D. Salary Changing (CF 1251 D)

    题目大意

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

    解题思路

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

    神奇的代码
    #include <bits/stdc++.h>
    #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<int> VI;
    typedef pair<int,int> PII;
    typedef vector<PII> VPII;
    typedef vector<LL> VL;
    typedef pair<LL,LL> PLL;
    typedef vector<PLL> VPLL;
    
    template <typename T>
    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 <typename T>
    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<pair<LL,LL>> sol,int n,LL s){
        int cnt=0;
        vector<LL> qwq;
        for(auto i:sol){
            if (i.second<mid) s-=i.first;
            else if (i.first>=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<m) return 0;
        sort(qwq.begin(),qwq.end());
        int cou=qwq.size()-(m-cnt);
        for(int i=0;i<cou;++i)
            s-=qwq[i];
        s-=(m-cnt)*mid;
        if (s<0) return 0;
        return 1;
    }
    
    int main(void) {
        int kase; read(kase);
        for (int i = 1; i <= kase; i++) {
            int n;
            LL s;
            read(n);
            read(s);
            vector<pair<LL,LL>> 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<r){
                LL mid=(l+r)>>1;
                if (check(mid,sol,n,s)) ans=mid,l=mid+1;
                else r=mid;
            }
            write(ans,'
    ');
        }
        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<cur)的人都已经投票给你了,记为(sum[i-1]),再加上自己已经贿赂了(py)个人,如果(sum[i-1]+pygeq cur)的,那这组人就归降于您,否则就需要再在(m_jgeq cur)的人中贿赂直到(sum[i-1]+py=cur)或都贿赂完,我们自然是贪心的找(p_i)最小的那些人贿赂,用优先队列维护即可。

    神奇的代码
    #include <bits/stdc++.h>
    #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<int> VI;
    typedef pair<int,int> PII;
    typedef vector<PII> VPII;
    typedef vector<LL> VL;
    typedef pair<LL,LL> PLL;
    typedef vector<PLL> VPLL;
    
    template <typename T>
    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 <typename T>
    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<int> 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<int,vector<int>,greater<int>> 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<i){
                    ans+=qwq.top();
                    qwq.pop();
                    ++by;
                }  
            }
            write(ans,'
    ');
        }
        return 0;
    }
    


    F. Red-White Fence (CF 1251 F)

    题目大意

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

    解题思路

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

    神奇的代码
    #include <bits/stdc++.h>
    #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<int> VI;
    typedef pair<int,int> PII;
    typedef vector<PII> VPII;
    typedef vector<LL> VL;
    typedef pair<LL,LL> PLL;
    typedef vector<PLL> VPLL;
    
    template <typename T>
    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 <typename T>
    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<size;++i)
            rev[i]=(rev[i>>1]>>1)|((i&1)?(size>>1):0);
        for(int i=0;i<size;++i)
            if (rev[i]>i) 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<size;i+=len){
                LL w=1;
                for(int j=0;j<(len>>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;i<size;++i)
                arr[i]=arr[i]*t%mod;
        }
    }
    
    LL C(int m,int n){
        if (m>n) 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<pos;++j){
                if (white[j]==white[j+1]) N+=2,++j;
                else ++M;
            }
            for(int j=0;j<=M;++j) a[j]=C(j,M)*qpower(2,j)%mod;
            for(int j=0;j<=N;++j) b[j]=C(j,N);
            ++M;
            ++N;
            int sz=1;
            g=3;
            while(sz<N+M) sz<<=1;
            NTT(a,sz,1);
            NTT(b,sz,1);
            for(int i=0;i<sz;++i)
                c[i]=a[i]*b[i]%mod;
            NTT(c,sz,-1);
            for(int j=0;j<max(pos,0);++j) ans[(red[i]<<1)+((j+1)<<1)]=(ans[(red[i]<<1)+((j+1)<<1)]+c[j])%mod;
            for(int j=0;j<sz;++j) a[j]=0;
            for(int j=0;j<sz;++j) b[j]=0;
            for(int j=0;j<sz;++j) c[j]=0;
        }
        read(q);
        for(int Q,i=1;i<=q;++i){
            read(Q);
            write(ans[Q],'
    ');
        }
        return 0;
    }
    


  • 相关阅读:
    https原理:证书传递、验证和数据加密、解密过程解析
    java web项目的https配置
    防止表单重复提交的八种简单有效的策略
    nginx.conf
    Java打war包or打jar包
    WarUtil
    MyBatis动态SQL第一篇之实现多条件查询(if、where、trim标签)
    Spring使用注解实现AOP
    Spring添加声明式事务
    spring配置文件拆分策略及方法
  • 原文地址:https://www.cnblogs.com/Lanly/p/12270915.html
Copyright © 2011-2022 走看看