zoukankan      html  css  js  c++  java
  • Codeforces Round #672 (Div. 2)(A->C2)(B位运算,C贪心,DP)

    A:http://codeforces.com/contest/1420/problem/A

    题意:

    最多交换n*(n-1)/2-1次,是否能把序列变成非递减序列

    解析:

    冒泡排序最差的情况是n*(n-1)/2,最差情况就是全递减。所以判断序列是否为单调递减即可。

    #include <bits/stdc++.h>
    #include<vector>
    using namespace std;
    typedef long long ll;
    const int maxn = 1e6+10;
    int a[maxn];
    int pr[maxn];
    bool st[maxn];
    //vector<int>g[maxn];
    int cnt=0;
    void _get(ll n)
    {
        memset(st,false,sizeof(st)); 
    
        for(int i=2;i<=n;i++)
        {
            if(!st[i])
            {
                pr[cnt++]=i;
            }
            for(int j=i+i;j<=n;j+=i)
            {
                st[j]=true;
            }
        }
    }
    int main(){
        int t;
        cin>>t;
        while(t--)
        {
            int n;
            cin>>n;
            for(int i=1;i<=n;i++)
                cin>>a[i];
            int ok=0;
            for(int i=2;i<=n;i++)
            {
                if(a[i-1]<=a[i])
                {
                    ok=1;break;
                }
            }
            if(ok)
                cout<<"YES"<<endl;
            else
                cout<<"NO"<<endl;
        }
    }

    B:http://codeforces.com/contest/1420/problem/B

    题意:

    存在几对(i,j),i<j满足:
    ai & ajaiaj

    解析:

    &运算:都为1,则为1,否则为0

    xor运算:不同则为1,相同则为0

    由此得出,对于ai和aj,只需要判断它们的二进制第一位是否相同即可。相同即能组成一对。

    我这边是统计的的ai最大能到几次幂,map记录。

    对于n个数,可以组成((n-1)^2+(n-1))/2对

    #include <bits/stdc++.h>
    #include<vector>
    #include<map>
    using namespace std;
    typedef long long ll;
    const int maxn = 1e6+10;
    ll a[maxn];
    int pr[maxn];
    bool st[maxn];
    //vector<int>g[maxn];
    int cnt=0;
    void _get(ll n)
    {
        memset(st,false,sizeof(st)); 
    
        for(int i=2;i<=n;i++)
        {
            if(!st[i])
            {
                pr[cnt++]=i;
            }
            for(int j=i+i;j<=n;j+=i)
            {
                st[j]=true;
            }
        }
    }
    int main(){
        int t;
        cin>>t;
        while(t--)
        {
            ll n;
            cin>>n;
            map<ll,ll>mm;
            for(int i=1;i<=n;i++)
            {
                cin>>a[i];
                int cnt=0;
                for(int j=0;j<33;j++)
                {
                    ll md=pow(2,j);
                    if(md>a[i])
                    {
                        mm[cnt]++;
                        break;
                    }
                    else
                    {
                        cnt=j;
                    }
                }
            //    cout<<cnt<<endl;
            }
            ll all=0;
            for(int i=0;i<32;i++)
            {
                if(mm[i]==0)
                    continue;
                ll md=mm[i];
                md=((md-1)*(md-1)+(md-1))/2;
                all+=md;
            }
            cout<<all<<endl;
        }
    }

    C1:http://codeforces.com/contest/1420/problem/C1

    题意:

    n,q

    n个数,q次交换(C1的q=0,无交换操作)

    找出最大的Ab1-Ab2+Ab3.....

    1<=b1<b2<b3....<=n

    解析:

    解法1:贪心找峰点和谷点

    经过分析,对于一段上升的序列,我们需要加上最高的那个点,对于一段递减的序列,我们需要减去最低的那个点

    所以就是峰点和谷点了,找这些点对即可。

    两种找寻方式:

    (1)比较麻烦,但是很巧妙,很锻炼人。L负责记录每一段上升序列的最大值,R记录每一段递减序列的最小值。

    #include <bits/stdc++.h>
    #include<vector>
    #include<map>
    using namespace std;
    typedef long long ll;
    const int maxn=3e5+10;
    int a[maxn];
    int pr[maxn];
    bool st[maxn];
    int main(){
        int t;
        cin>>t;
        while(t--)
        {
            int n,q;
            cin>>n>>q;
            for(int i=1;i<=n;i++)
                cin>>a[i];
            int l = 0 , r = 0;
            ll sum=0;
            for(int i=1;i<=n;i++)
            {
                if(i==1)
                {
                    l=a[i];
                }
                else
                {
                    if(a[i]>a[i-1])
                    {
                        if(l&&r)
                            sum+=l-r;
                        l=a[i];
                        r=0;
                    }
                    else
                    {
                        r=a[i];
                    }
                }
            }
            sum+=l;//注意
            cout<<sum<<endl;
        }
    }

    (2)直接判断峰谷点。

    #include <bits/stdc++.h>
    #include<vector>
    #include<map>
    using namespace std;
    typedef long long ll;
    const int maxn=3e5+10;
    int a[maxn];
    int pr[maxn];
    ll dp1[maxn],dp2[maxn];
    bool st[maxn];
    int main(){
        int t;
        cin>>t;
        while(t--)
        {
            int n,q;
            cin>>n>>q;
            for(int i=1;i<=n;i++)
                cin>>a[i];
            ll sum=0;
            a[0]=0,a[n+1]=0;
            for(int i=1;i<=n;i++)
            {
                if(a[i]>a[i-1]&&a[i]>a[i+1])
                    sum+=a[i];
                if(a[i]<min(a[i-1],a[i+1]))
                    sum-=a[i];    
            }
            cout<<sum<<endl;
        }
    }

    解法2:DP

    规定dp1[i]表示,在i位置,所选序列长度为奇数,那么对于当前ai,选或者不选。不选的话dp1[i-1],选的话,利用上次的偶数长度dp2[i-1]+a[i]

    dp2[i]同理,在i位置,所选序列长度为偶数。

    #include <bits/stdc++.h>
    #include<vector>
    #include<map>
    using namespace std;
    typedef long long ll;
    const int maxn=3e5+10;
    int a[maxn];
    int pr[maxn];
    ll dp1[maxn],dp2[maxn];
    bool st[maxn];
    int main(){
        int t;
        cin>>t;
        while(t--)
        {
            int n,q;
            cin>>n>>q;
            for(int i=1;i<=n;i++)
                cin>>a[i];
            for(int i=1;i<=n;i++)
            {
                dp1[i]=max(dp1[i-1],dp2[i-1]+a[i]);
                dp2[i]=max(dp2[i-1],dp1[i-1]-a[i]);
            }
            cout<<max(dp1[n],dp2[n])<<endl;
        }
    }

    C2:http://codeforces.com/contest/1420/problem/C2

    承接上述的解法1,直接判断谷点的解法。

    对于一个位置i,如果它被交换掉,那么就会对相邻的i-1,i+1产生影响。即,三个点都受到了影响。那么交换一次,就需要对之前的统计操作进行取消,即:

    void del(int i)
    {
        if(!f[i]||i==0||i==n+1)
            return ;
        f[i]=0;
        if(a[i]>max(a[i-1],a[i+1]))
            sum-=a[i];
        else if(a[i]<min(a[i-1],a[i+1]))
            sum+=a[i];
        return ;    
    }
                del(l-1);del(l);del(l+1);
                del(r-1);del(r);del(r+1);

    引入f[],防止重复取消或统计。

    取消以后,进行对应的交换。

    进行重新统计,统计也是仅限于这三个点,因为这几个点是否是峰谷点的属性本身有可能发生改变,对总体答案只是局部的影响。

    具体的见代码吧:

    #include <bits/stdc++.h>
    #include<vector>
    #include<map>
    using namespace std;
    typedef long long ll;
    const int maxn=3e5+10;
    int a[maxn],n,f[maxn];
    //int pr[maxn];
    //ll dp1[maxn],dp2[maxn];
    //bool st[maxn];
    ll sum=0;
    void insert(int i)
    {
        if(f[i]||i==0||i==n+1)
            return ;
        f[i]=1;
        if(a[i]>max(a[i-1],a[i+1]))
            sum+=a[i];
        else if(a[i]<min(a[i-1],a[i+1]))
            sum-=a[i];
        return ;
    }
    void del(int i)
    {
        if(!f[i]||i==0||i==n+1)
            return ;
        f[i]=0;
        if(a[i]>max(a[i-1],a[i+1]))
            sum-=a[i];
        else if(a[i]<min(a[i-1],a[i+1]))
            sum+=a[i];
        return ;    
    }
    int main(){
        int t;
        cin>>t;
        while(t--)
        {
            int q;
            cin>>n>>q;
            for(int i=1;i<=n;i++)
                cin>>a[i],f[i]=0;
            a[0]=0;a[n+1]=0;
            sum=0;
            for(int i=1;i<=n;i++)
                insert(i);
            cout<<sum<<endl;
            while(q--)
            {
                int l,r;
                cin>>l>>r;
                del(l-1);del(l);del(l+1);
                del(r-1);del(r);del(r+1);
                swap(a[l],a[r]);
                insert(l-1);insert(l);insert(l+1);
                insert(r-1);insert(r);insert(r+1);
                cout<<sum<<endl;
            }
        }
    }
  • 相关阅读:
    永久破解之phpstorm
    CPU线程和Java线程
    kvm自动扩容内存
    swoole http server 信息
    mac 安装PHP redis扩展phpredi-5.0.2
    el-tree,很恶心的树,就从默认展开节点开始吧
    转开发啦,就从最基础的数据转换开始吧
    Java集合系列-HashSet
    Java基础系列-单例的7种写法
    Java基础系列-Lambda
  • 原文地址:https://www.cnblogs.com/liyexin/p/13732892.html
Copyright © 2011-2022 走看看