zoukankan      html  css  js  c++  java
  • Codeforces Round #189 (Div. 2) 解题报告

    ----------------

    A. Magic Numbers

    一个神奇的数字是由1、14、144连接而成的,判断一个数字是不是神奇数字。

    ----

    ①没有连续3个以上的4。

    ②首位不能为4。

    数据范围太大,最好按字符读入。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    
    char c;
    int n,num;
    bool flag;
    
    int main()
    {
        flag=true;
        num=0;
        n=0;
        while (cin>>c)
        {
            if (n==0&&c!='1')
            {
                flag=false;
                break;
            }
            if (c!='1'&&c!='4')
            {
                flag=false;
                break;
            }
            if (c=='4') num++;
            else num=0;
            if (num>2)
            {
                flag=false;
                break;
            }
            n++;
        }
        if (flag) cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
        return 0;
    }
    
    ----------------

    B. Ping-Pong (Easy Version)

    两个数对(a,b)、(c,d),若c < a < d or c < b < 则数对(a,b)到数对(c,d)存在一条有向边。

    ① 1 a b 表示添加数对(a,b)

    ② 2 a b 询问是否有一条路径由第a个数对到第b个数对。

    ----

    按要求建边,dfs判断是否连通即可。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    int n;
    bool a[111][111];
    int x[111],y[111];
    bool vis[111]={0};
    
    bool dfs(int u,int v)
    {
        vis[u]=true;
        if (u==v) return true;
        for (int i=0;i<n;i++)
            if (a[u][i]&&!vis[i])
                if (dfs(i,v)) return true;
        return false;
    }
    
    int main()
    {
        int T;
        n=0;
        memset(a,0,sizeof(a));
        cin>>T;
        while (T--)
        {
            int t;
            cin>>t;
            if (t==1)
            {
                cin>>x[n]>>y[n];
                for (int i=0;i<n;i++)
                {
                    if ((x[i]<x[n]&&x[n]<y[i])||(x[i]<y[n]&&y[n]<y[i])) a[n][i]=true;
                    if ((x[n]<x[i]&&x[i]<y[n])||(x[n]<y[i]&&y[i]<y[n])) a[i][n]=true;
                }
                n++;
            }
            if (t==2)
            {
                int x,y;
                cin>>x>>y;
                memset(vis,0,sizeof(vis));
                if (dfs(x-1,y-1)) cout<<"YES"<<endl;
                else cout<<"NO"<<endl;
            }
        }
        return 0;
    }
    
    ----------------

    C. Malek Dance Club

    A组织的2^n个人与B组织的2^n配对跳舞。

    配对规则为一个长度为n的二进制串x。

    A组织的第i个人与B组织的第(i异或x)个人跳舞。

    若有(a, b(c, d)配对,若 a < c and b > d. 则有一个配对的复杂度。

    给出x,问两个组织配对跳舞的复杂度。结果mod1000000007 。

    ----

    有图有真相。。。


    图中左右两侧的点为A、B两组织的人员i的二进制编号,上方的x为异或用的二进制串。

    在配对的两个人之间连一条线,则配对复杂度即为交点的个数。

     假设已经解决了二进制串x,现在要计算1x和0x的值。

    此时已经计算出了f(x)的值。

    由图观察可知:

    ①f(0x)=2*f(x)。

    (设左右侧原来的编号为e,现在编号变为1e和0e,左0e和右0e配对,左1e和右1e配对,交点变为原来的2倍)

    (而左侧0e和右侧1e之间并没有增加新交点,总交点数变为以前的2倍)

    ②f(1x)=2*f(x)+4^n。

    (编号变为1e和0e交点变为以前的2倍,而左0e与右1e配对,左1e与右0e配对,左0e与右0e产生了2^n个新交点,同理左1e与右1e产生了2^n个新交点)

    (共增加了4^n个交点)

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    #include <string>
    
    using namespace std;
    
    const int maxn=111;
    const int MOD=1000000007;
    long long f[maxn];
    int n;
    string x;
    long long pw[maxn];
    
    int main()
    {
        pw[0]=1;
        for (int i=1;i<=100;i++)
        {
            pw[i]=pw[i-1]*4%MOD;
        }
        while (cin>>x)
        {
            n=x.length();
            f[n]=0;
            for (int i=n-1;i>=0;i--)
            {
                if (x[i]=='0') f[i]=2*f[i+1];
                if (x[i]=='1') f[i]=2*f[i+1]+pw[(n-i-1)];
                f[i]%=MOD;
            }
            cout<<f[0]<<endl;
        }
        return 0;
    }
    
    ----------------

    D. Psychos in a Line

    n个人排成1排,每个人有一个SAN值。

    每一回合,若一个人SAN值大于右边人的SAN值,则右边的人被杀。

    所有杀害同时发生。剩下的人重新排列。

    问多少回合后没有杀害发生。

    ----

    题解暂无。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <stack>
    #include <queue>
    #include <cmath>
    
    using namespace std;
    
    const int maxn=111111;
    const int INF=1e9+7;
    int f[maxn];
    int a[maxn];
    int n;
    stack<int>stk;
    
    int main()
    {
        int ans;
        while (cin>>n)
        {
            ans=0;
            while (!stk.empty()) stk.pop();
            memset(f,0,sizeof(f));
            for (int i=1;i<=n;i++) cin>>a[i];
            f[0]=INF;
            stk.push(0);
            for (int i=1;i<=n;i++)
            {
                f[i]=1;
                while (!stk.empty()&&a[i]>a[stk.top()])
                {
                    f[i]=max(f[i],f[stk.top()]+1);
                    stk.pop();
                }
                stk.push(i);
                if (f[i]<INF) ans=max(ans,f[i]);
            }
            cout<<ans<<endl;
        }
        return 0;
    }
    
    ----------------

    E. Kalila and Dimna in the Logging Industry

    Kalila和Dimna两个豺狼生活在一个巨大的丛林。有一天,他们为了赚钱加入了一个伐木厂。

    伐木场的经理希望他们去树林里砍高度为a1,a2,a3…an的n课树。他们从一家商店里买了一台链锯。每次在编号为i的树上使用链锯,他们都能减少这棵树的一个单位高度。每次Kalila和Dimna使用链锯,他们需要重新对它充电。充电的成本依赖于已经被完全切断的树的编号id(一棵树高度为0时被完全切断)。如果被完全切断的树最大的编号为i(树一开始高度为ai),那么对链锯充电的成本为bi。如果没有树被完全切断,Kalila和Dimna不能对链锯充电。链锯在伐木开始之前已经充电。我们已知对于每个i<j,ai<aj并且bi>bj,而且bn=0、a1=1。Kalila和Dimna希望用最低的成本砍完所有的树木。

    他们希望你来帮助他们,你会吗?

    INPUT

    第一行包含一个整数n (1 ≤ n ≤ 105),第二行包含n个整数a1,a2,a3…an (1 ≤ ai ≤ 109),第三行包含n个整数,b1,b2,b3….bn (0 ≤ bi ≤ 109)。

    保证a1=1,bn=0,a1<a2<...<an并且b1>b2>…>bn

    OUTPUT

    输出只有一行,砍完所有树木的最低成本。

    ----

    斜率DP

    令f[i]为完全砍断第i棵树的最低成本。

    如果最后一棵被砍断的树的编号为j,则f[i]=f[j]+a[i]*b[j]。

    因此f[i]=min(f[j]+a[i]*b[j]) ( j<i )

    简单dp时间复杂度为O(N*N)会超时,使用斜率优化可以变为O(N)的复杂度。

    /*
    //f[i]=min(f[j]+a[i]*b[j]) j<i
    //-a[i]*b[j]+f[i]=f[j]
    //令f[j]为y,b[j]为x,-a[i]为k,截距为dp[i]
    */
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <string>
    #include <cmath>
    
    using namespace std;
    
    typedef long long LL;
    
    const int maxn=111111;
    
    LL a[maxn],b[maxn],f[maxn];
    int n;
    int que[maxn*4];
    int head,tail;
    //y1-y2
    LL fun(int k1,int k2){
        return f[k1]-f[k2];
    }
    //y1-y2>=k*(x1-x2)
    bool cmp_head(int k1,int k2,int i){
        return fun(k1,k2)>=-a[i]*(b[k1]-b[k2]);
    }
    //y1-y2/x1-x2>=y2-yi/x2-xi
    bool cmp_tail(int k1,int k2,int i){
        return double(fun(k1,k2))/double(b[k1]-b[k2])>=double(fun(k2,i))/double(b[k2]-b[i]);
    }
    //y-kx
    LL dp_sol(int i,int j){return f[j]+a[i]*b[j];}
    //y1-y2/x1-x2
    double k_sol(int i,int j){return double(f[i]-f[j])/double(b[i]-b[j]);}
    
    int main()
    {
        while (cin>>n)
        {
            memset(f,0,sizeof(f));
            for (int i=0;i<n;i++) cin>>a[i];
            for (int i=0;i<n;i++) cin>>b[i];
            head=tail=0;
            que[tail++]=0;
            f[0]=0;
            for (int i=1;i<n;i++)
            {
                while (tail-head>1&&dp_sol(i,que[head])>=dp_sol(i,que[head+1])) head++;
                //while (tail-head>1&&cmp_head(que[head],que[head+1],i)) head++;
                f[i]=dp_sol(i,que[head]);
                while (tail-head>1&&k_sol(i,que[tail-1])>=k_sol(que[tail-1],que[tail-2])) tail--;
                //while (tail-head>1&&cmp_tail(que[tail-2],que[tail-1],i) ) tail--;
                que[tail++]=i;
            }
            cout<<f[n-1]<<endl;
        }
        return 0;
    }
    


    ----------------

  • 相关阅读:
    生成函数
    泰勒公式与牛顿迭代
    如何在浏览器关闭发送请求
    elment-ui table组件 -- 远程筛选排序
    微信小程序 -- 数据请求
    2019年 学习计划
    vue 表单校验(二)
    ubuntu 学习
    vue-cli如何添加多种环境变量
    vue兼容ie
  • 原文地址:https://www.cnblogs.com/cyendra/p/3226283.html
Copyright © 2011-2022 走看看