• Educational Codeforces Round 80 (Rated for Div. 2)


    A. Deadline (CF 1288 A)

    题目大意

    给定(n,d),问是否存在自然数(x),使得(x+left lceil dfrac{d}{x+1} ight ceil leq n)

    解题思路

    直接暴力。对于用了不等式的不会去证明其正确性qwq整除与上下取正什么的。

    神奇的代码
    #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(int n,int d){
        for(int i=1;i<MIN(1e5,n);++i){
            if (i+(int)ceil(d*1.0/(i+1))<=n) return true;
        }
        return false;
    }
    
    int main(void) {
        int kase; read(kase);
        for (int i = 1; i <= kase; i++) {
            // printf("Case #%d: ", i);
            int n,d;
            read(n);
            read(d);
            if (n>=d||check(n,d)) puts("YES");
            else puts("NO");        
        }
        return 0;
    }
    


    B. Yet Another Meme Problem (CF 1288 B)

    题目大意

    给定(A,B),问有对少个((a,b)),其中(a in [1,A],b in [1,B]),使得(a imes b+a+b=a imes 10^{f(b)}+b),其中(f(x))表示(x)的位数。

    解题思路

    我们把式子化简,即为(b+1=10^{f(b)}),很显然b只能为(9,99,999)这样的类型,我们设(b+1)(cnt)位,那答案就是(cnt imes 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++) {
            LL A,B;
            read(A);
            read(B);
            LL qwq=9;
            int tmp=0;
            while(qwq<=B){
                ++tmp;
                qwq=qwq*10+9;
            }
            LL ans=tmp*A;
            printf("%lld
    ",ans);
        }
        return 0;
    }
    


    C. Two Arrays (CF 1288 C)

    题目大意

    给定(n,m),要求构造两个数组(a,b),记为((a,b)),满足(a,b)数组有(m)个元素,且(forall i in [1,m],1leq a_ile b_i leq n),问有多少个符合要求的((a,b))

    解题思路

    我们设(dp0[i][j])表示当前第(i)位放(j)且不严格递增的方案数,则(dp0[i][j]=sumlimits_{k=1}^{j}dp0[i-1][k]),相应的再设个不严格递减的方案数(dp1[i][j]),最终答案就是(sumlimits_{i=1}^{n}sumlimits_{j=i}^{n}dp0[n][i] imes dp1[n][j])
    对应为代码注释部分。

    我们把(b)数组翻转过来,接到(a)后面,我们就得到了一个长度为(2m)的不严格递增的数组(c),这样问题就是我们能够构造出多少个长度为(2m)的不严格递增的数组,当然也可以按照上面来次动态规划可以解决。不过可以证明,答案就是

    [C^{n-1}_{2m+n-1} ]

    我们记(cnt_i)表示数(i)在数组(c)出现的次数,则有(sumlimits_{i=1}^{n}cnt_i=2 imes m),答案就是该方程组的非负整数解组的个数。这是个经典的排列组合问题,由于用隔板法要求解为正整数,而这里(cnt_i)可以为(0),那么我们就等式左右两边都加一个(n),并令(CNT_i=cnt_i+1),这样方程(sumlimits_{i=1}^{n}CNT_i=2 imes m)的解都是正整数,根据隔板法(假设有(2m)个球,插(n-1)个板把求分为(n)组,每组的个数即为(cnt_i),排序)答案就是(C^{n-1}_{2m+n-1})

    还有个证明方法就是我们构造一个(d)数组,其中(d_i=c_i+i),则(2leq d_i leq 2m+n),可以证明每个(d)数组恰与一个(c)数组对应并不会证明,注意到(d)数组数字各异,所以(d)数组共有(C_{2m+n-1}^{2m}=C_{2m+n-1}^{n-1})

    神奇的代码
    #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 mo=1e9+7;
    
    LL kuai(LL a,LL b){
        LL qwq=1;
        while(b){
            if (b&1) qwq=qwq*a%mo;
            a=a*a%mo;
            b>>=1;
        }
        return qwq;
    }
    
    LL C(int n,int m){
        LL qwq=1,tmp=1;
        for(int i=1;i<=n;++i) qwq=qwq*i%mo; 
        for(int i=1;i<=m;++i) tmp=tmp*i%mo; 
        qwq=qwq*kuai(tmp,mo-2)%mo;
        tmp=1;
        for(int i=1;i<=n-m;++i) tmp=tmp*i%mo; 
        qwq=qwq*kuai(tmp,mo-2)%mo;
        return qwq;
    }
    
    int main(void) {
        int n,m;
        read(n);
        read(m);
        LL ans=C(2*m+n-1,n-1);
        /* LL dp0[m+1][n+1],dp1[m+1][n+1];
        for(int i=1;i<=n;++i) dp0[1][i]=dp1[1][i]=1;
        for(int i=2;i<=m;++i){
            LL sum=0;
            for(int j=1;j<=n;++j){
                sum=(sum+dp0[i-1][j])%mo;
                dp0[i][j]=sum;
            }
        }
        for(int i=2;i<=m;++i){
            LL sum=0;
            for(int j=n;j>=1;--j){
                sum=(sum+dp1[i-1][j])%mo;
                dp1[i][j]=sum;
            }
        }
        LL ans=0;
        for(int i=1;i<=n;++i)
            for(int j=i;j<=n;++j)
                ans=(ans+dp0[m][i]*dp1[m][j]%mo)%mo; */
        printf("%lld
    ",ans);
        return 0;
    }
    


    D. Minimax Problem (CF 1288 D)

    题目大意

    给定(n)个数组(a_i),每个数组有(m)个数,要求选择两组数组(i,j),最大化(minlimits_{1leq k leq m} (max (a_{ik},a_{jk})))。输出(i,j)。注意:(1leq n leq 3 imes 10^5,1leq m leq 8)

    解题思路

    我暴力就(O(n^2m))能怎么优化捏……但(m)是出奇的小。
    注意到(min)的值可行性具有单调性,我们考虑如何快速判定它的可行性。
    我们先二分最小值(qwq),枚举了一组,我们要看能否存在另一组,把该组小于(qwq)的值变成大于等于(qwq)。那么对于一组数组的某一位,如果它大于等于就设为(1),否则为(0),这样我们就把某一组(hash)成一个数字(num_i),那么对于一组(i),对应了一个数字(num_i),如果还有另一组(j)对应的数字(num_j)两者(|)一下得到的数字是(num_i|num_j)(2^m-1)的话,这就说明这两组结合起来,它的最小值是大于等于(qwq),而数字(num_j)也就只有(2^m-1leq 255)

    于是我们就二分最小值,然后枚举一组,再枚举各位大于(qwq)的所有情况即可。时间复杂度(O(n imes 2^mlog_2max(a_{ij})))

    神奇的代码
    #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 int N=3e5+8;
    
    int n,m,x,y;
    
    pair<bool,int> sign[260];
    
    int a[N][10],v[N];
    
    bool check(int val){
        memset(sign,0,sizeof(sign));
        for(int i=0;i<n;++i){
            int qwq=0;
            for(int j=0;j<m;++j)
                if (a[i][j]>=val) qwq|=(1<<j);
            sign[qwq]=make_pair(true,i);
            v[i]=qwq;
        }
        if (sign[(1<<m)-1].first==true){
            x=y=sign[(1<<m)-1].second+1;
            return true;
        }
        for(int i=0;i<n;++i)
            for(int j=0;j<(1<<m);++j){
                if (!sign[j].first) continue;
                int qwq=v[i]|j;
                if (qwq!=(1<<m)-1) continue;
                x=i+1;
                y=sign[j].second+1;
                return true;
            }
        return false;
    }
    
    int main(void) {
        read(n);
        read(m);
        int l=1e9+7,r=0;
        for(int i=0;i<n;++i)
            for(int j=0;j<m;++j){
                read(a[i][j]);
                l=MIN(l,a[i][j]);
                r=MAX(r,a[i][j]);
            }  
        x=y=0;
        ++r;
        while(l<r){
            int mid=(l+r)>>1;
            if (check(mid)) l=mid+1;
            else r=mid;
        }
        printf("%d %d
    ",x,y);
        return 0;
    }
    


    E. Messenger Simulator (CF 1288 E)

    题目大意

    你有(n(nleq 3 imes 10^5))个好友(这说明你与世界总人口的万分之一的人认识/滑稽),初始标号(1-n)排列,然后你依次收到了(m)条短信,第(i)条短信是来自是(a_i),当收到第(a_i)个好友发来的信息时,它会飞到列表的第一个并且在它前面的其他人都会后退一位,当然如果本身在第一位就什么事都没发生,除了你收到了条短信。问每个人位置最小和最大分别是多少。

    解题思路

    对于某个人(i)来说,如果它发过消息那么位置最小就是(1),没有发过消息则是(i),我们只用解决位置最大是多少。

    对于某个人(i),它第一次出现的时候,由于只有序号比它大的才会对它的位置有影响,那么它此时已经后退了(b)位,位居(i+b)位,这里(b)是在(i)前面,比(j)大且互不相同的数的个数。而当(i)第二次出现的时候,(i)后退的(B)位,这里(B)是在(i)第一次出现之后第二次出现之前的数互不相同的个数,之后的处理类似。注意到如果我们在数列里前面加上(n,n-1,n-2,n-3,...,1)来初始化局面,那么在这之后对于(i)出现的情况的处理都类似(i)第二次出现了。

    那么现在问题就转换成了统计区间内互不相同的个数。这个用(Fenwick Tree)或者(Segment Tree)来维护就好了。维护位置对个数的贡献,从左到右遍历,遇到第二次出现的就统计前后两次出现之间的位置对答案的贡献,然后把第一次出现的位置对答案的贡献置为(0),第二次出现的位置对答案的贡献置为(1),就能统计区间互不相同的个数了。

    神奇的代码
    #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 int N=6e5+8;
    
    struct BIT_TREE{
        int cnt[N];
    
        int lowbit(int x){
            return (x&(-x));
        }
    
        void updata(int pos,int tot,int val){
            for(int i=pos;i<=tot;i+=lowbit(i))
                cnt[i]+=val;
        }
    
        int sum(int pos){
            int qwq=0;
            for(int i=pos;i>=1;i-=lowbit(i))
                qwq+=cnt[i];
            return qwq;
        }
    
        int query(int l,int r){
            if (l>r) return 0;
            return sum(r)-sum(l-1);
        }
    }BIT;
    
    int main(void) {
        int n,m;
        read(n);
        read(m);
        int v[n+m+5];
        for(int i=1;i<=n;++i)
            v[i]=n-i+1;
        for(int i=1;i<=m;++i)
            read(v[i+n]);
        int sign[n+m+5]={0};
        int pos[n+5][2]={0};
        for(int i=1;i<=n;++i) pos[i][0]=pos[i][1]=i;
        for(int i=1;i<=n+m;++i){
            if (sign[v[i]]==0){
                sign[v[i]]=i;
                BIT.updata(i,n+m,1);
            }
            else{
                int qwq=BIT.query(sign[v[i]]+1,i-1)+1;
                pos[v[i]][0]=1;
                pos[v[i]][1]=MAX(pos[v[i]][1],qwq);
                BIT.updata(sign[v[i]],n+m,-1);
                BIT.updata(i,n+m,1);
                sign[v[i]]=i;
            }
        }
        for(int i=1;i<=n;++i) pos[i][1]=max(pos[i][1],BIT.query(sign[i]+1,n+m)+1);
        for(int i=1;i<=n;++i)
            printf("%d %d
    ",pos[i][0],pos[i][1]);
        return 0;
    }
    


    F. Red-Blue Graph (CF 1288 F)

    题目大意

    给定一个二分图,注意这里可能有重边,然后对边染色,染成红色费用(r),染成蓝色费用(b),对于一个点,如果连接它的红色边数量严格大于蓝色边,则这个点被染成红色;如果连接它的蓝色边数量严格大于红色边,则这个点被染成蓝色;否则它不被染色。现在给定点染色的要求(URB),对应未染色,红色,蓝色,球给定一组边染色的方案,使得点被染成给定要求,且费用最小。

    解题思路

    玄学构图+费用流

    神奇的代码
    qwq
    


  • 相关阅读:
    20200209 ZooKeeper 3. Zookeeper内部原理
    20200209 ZooKeeper 2. Zookeeper本地模式安装
    20200209 Zookeeper 1. Zookeeper入门
    20200206 尚硅谷Docker【归档】
    20200206 Docker 8. 本地镜像发布到阿里云
    20200206 Docker 7. Docker常用安装
    20200206 Docker 6. DockerFile解析
    20200206 Docker 5. Docker容器数据卷
    20200206 Docker 4. Docker 镜像
    Combining STDP and Reward-Modulated STDP in Deep Convolutional Spiking Neural Networks for Digit Recognition
  • 原文地址:https://www.cnblogs.com/Lanly/p/12196794.html
Copyright © 2020-2023  润新知