zoukankan      html  css  js  c++  java
  • 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
    


  • 相关阅读:
    王者齐聚!Unite 2017 Shanghai 日程讲师全揭晓
    微软在.NET官网上线.NET 架构指南频道
    期待微软平台即服务技术Service Fabric 开源
    Visual Studio 20周年软件趋势随想
    .NET 十五岁,谈谈我眼中的.NET
    API网关Ocelot 使用Polly 处理部分失败问题
    互联网背景下知识半衰期这么短,如何学习?
    CentOS 7 上面安装PowerShell
    搭建consul 集群
    Entity Framework Core 实现MySQL 的TimeStamp/RowVersion 并发控制
  • 原文地址:https://www.cnblogs.com/Lanly/p/12196794.html
Copyright © 2011-2022 走看看