zoukankan      html  css  js  c++  java
  • Cleaning(CF1474D)

    题意:
    (n)堆石头,每堆石头的石头个数为(a[i]),每次操作可以选择相邻的两堆石头(两堆石头的数量必须大于 (0) ),让这两堆的数量都减少 (1)。相邻关系的成立由最开始确定,在其中某一堆石头个数为 (0) 以后,这堆石头的左边和右边并不会变成相邻)。问在至多交换其中相邻两堆石头一次的条件下,再经过无数次上述操作后,石头总数有没有可能变成 (0)


    想法:

    • 首先考虑在没有交换次序时,如何判断这些石头能不能消除。可以发现消除一定是从两端开始,比如 (a[1] 和 a[2])消除时,结果必定是 (a[1]=0,a[2]=a[2]-a[1]),以此类推,我们可以发现在消除 (a[i] 和 a[i+1]) 时,如果 $ a[i+1]<a[i] $ ,则无法再消除。由于对称,从右向左也是如此。我们可以用 (L[i]和R[i]) 来表示在第i堆石头中,从左边开始消除时,剩下(L[i])个石头;从右边开始消除时,剩下(R[i])个石头。那么只要有一个i满足 (L[i]==R[i+1]) 时,这n堆石头是可消除的。

    • 接下来看可以交换相邻次序,因为是交换相邻次序,所以直接遍历这(n-1)种情况,设(a[i]和a[i+1])交换次序,那么从第一段的结论来看,只要(L[i-1])(a[i+1])(a[i])(R[i+2])这组数据满足可以消除的条件即可,那么我们可以直接去暴力判断其是否满足。

    • 由于上述讲到的情况中无法对 (a[1])(a[2])(a[n-1])(a[n])两种角落的交换,以及n=1时的判断都没有提到,因此再特判即可。


    代码:

    ll L[MAXN],R[MAXN],a[MAXN],b[MAXN];
    int n;
    bool check()
    {
        int pos;
        for(int i=2;i<=n;i++){
            if(b[i]<b[i-1]){
                return 0;
            }
            b[i]-=b[i-1];
        }
        return b[n]==0;
    }
    bool check2(int i)
    {
        ll now[10];
        now[1]=L[i-1];
        now[2]=a[i+1];
        now[3]=a[i];
        now[4]=R[i+2];
        for(int j=2;j<=4;j++){
            if(now[j]<now[j-1]){
                return 0;
            }
            now[j]-=now[j-1];
        }
        return now[4]==0;
    }
    int solve()
    {
       
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%lld",&a[i]);
            L[i]=-INF;
            R[i]=-INF;
            b[i]=a[i];
        }
        a[0]=0;
        a[n+1]=0;
        if(n==1){
            return 0;
        }
        if(check())return 1;
        for(int i=0;i<=n+1;i++)b[i]=a[i];
    
        swap(b[1],b[2]);
        if(check())return 1;
    
        for(int i=0;i<=n+1;i++)b[i]=a[i];
    
        swap(b[n],b[n-1]);
        if(check())return 1;
    
        for(int i=0;i<=n+1;i++)b[i]=a[i];
        for(int i=1;i<=n;i++){
            if(b[i-1]>b[i]){
                break;
            }else{
                L[i]=b[i]-=b[i-1];
            }
        }
        for(int i=0;i<=n+1;i++)b[i]=a[i];
        for(int i=n;i>=1;i--){
            if(b[i]<b[i+1]){
                break;
            }else{
                R[i]=b[i]-=b[i+1];
            }
        }
        for(int i=1;i<=n;i++)b[i]=a[i];
        for(int i=2;i<=n-2;i++){  //L[i-1],a[i+1],a[i],R[i+2]
            if(L[i-1]==-INF||R[i+2]==-INF)continue;
            if(check2(i))return 1;
        }
        return 0;
    }
    
    int main()
    {
        int T;
        cin>>T;
        while(T--){
            if(solve())cout<<"YES"<<endl;
            else cout<<"NO"<<endl;
        }
    }
    
    越自律,越自由
  • 相关阅读:
    6 全局锁和表锁
    oracle ogg--ogg搭建过程中遇到的错误及处理
    5 深入浅出索引(下)
    4 深入浅出索引(上)
    oracle ogg 单实例双向-新增表,修改表结构(oracle-oracle
    oracle ogg 单实例双向复制搭建(oracle-oracle)--Oracle GoldenGate
    Iview 中 获取 Menu 导航菜单 选中的值
    idea中git分支的使用
    vue使用axios进行ajax请求
    web前端_Vue框架_设置浏览器上方的标题和图标
  • 原文地址:https://www.cnblogs.com/ha-chuochuo/p/14308793.html
Copyright © 2011-2022 走看看