补题*总结题21/9/11

A - Super-palindrome(思维)

题意:
给一个字符串,问修改最少多少次,把给定字符串修改成超级回文串。
“超级回文串”的定义:对于所有长度为奇数的子串,都是回文的字符串就是超级回文串,
思路:
枚举发现:
 超级回文串就是奇数位是同一个字符,偶数位是同一字符。
所以:
 直接统计奇数位上最多的字符数量sum1,偶数位上最多的字符数量sum2,答案一定是n-sum1-sum2,(n为给定串长度)。
代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int main()
{
    int t;
    cin>>t;
  while (t--)
  {
      char a[101];
      cin>>a;
      int len=strlen(a);
      int b[27]={0};
      int c[27]={0};
      for(int i=0;i<len;i++)
      {
          if(i%2==0) b[ a[i]-'a' ]++;
          else
            c[ a[i]-'a'  ]++;
      }
      int bmax=0;
      int cmax=0;
      int bsum=0;
      int csum=0;
            for(int i=0;i<27;i++)
      {
          bsum+=b[i];
          csum+=c[i];
          if(bmax<b[i]) bmax=b[i];
          if(cmax<c[i])  cmax=c[i];
      }
      cout<<csum-cmax+bsum-bmax<<endl;
  }
    return 0;
}

C - Hakase and Nano(博弈+规律)

题意:
有T组数据,
每组数据输入一个n(石子堆的数目)d(1表示Ha先取,2表示Na先取)
然后输入n个数据表示第i堆石子有ai个石子。
要求:

  • 每一次取:可以去任意一堆石子取石子,但最少取一个,
  • Hakase每次必须取两次,Nano每次必须取一次。
  • Hakase赢就输出Yes否则输出No。
    思路:
    博弈的关键是找到必输(赢)情况,然后看其他情况怎么能转化为必输情况
    通过枚举发现,
    Ha先手:Ha必输情况是n是3的倍数+a[i]都是1,其余情况都是赢
    故反推
    Na先手:Ha必输的情况是Na通过一步操作可以达到,Ha必输的情况
    即:
  1. H在n是3的倍数,且有n-1个数为1时会输(这时N只需从不是1的那堆石子里拿掉一些石子使状态变为1 1 1)
  2. n是3的倍数余1,且n个数为1时会输(此时N只需拿掉一堆石子,H就到了必输态),
  3. n是3的倍数余1,且n-1个数为1时会输(此时N只需拿掉一堆不是1的石子,H就到了必输态)。
    代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long

int main()
{
    int t;
    scanf("%d",&t);
    while (t--)
    {
        int  n,d;
        scanf("%d%d",&n,&d);
        int a[n+2];
        for(int i=0; i<n; i++)
        {
            cin>>a[i];
        }
        if(n==1)
        {
            if(d==1)
            {
                cout<<"Yes"<<endl;
                continue;
            }
            else
            {
                cout<<"No"<<endl;
                continue;
            }
        }
        if(n==2)
        {
            cout<<"Yes"<<endl;
            continue;
        }

        sort(a,a+n);

        if(n==3)
        {

            if(a[0]==1&&a[1]==1&&a[2]==1)
            {

                if(d==1)
                {
                    cout<<"No"<<endl;
                    continue;
                }
                else
                {
                    cout<<"Yes"<<endl;
                    continue;
                }
            }

            if(a[0]==1&&a[1]==1&&a[2]>1)
            {
                if(d==1)
                {
                    cout<<"Yes"<<endl;

                    continue;
                }
                else
                {
                    cout<<"No"<<endl;
                    continue;
                }
            }

            if(a[0]==1&&a[1]>1&&a[2]>1)
            {
                if(d==1)
                {
                    cout<<"Yes"<<endl;
                    continue;
                }
                else
                {
                    cout<<"Yes"<<endl;
                    continue;
                }
            }
        }

        if(n>=4)
        {
            int o=a[n-2];
            if(d==1)
            {
                if(n%3==0&&a[n-1]==1)
                {
                    cout<<"No"<<endl;
                    continue;
                }
                else
                {
                    cout<<"Yes"<<endl;
                    continue;
                }
            }
            else
            {
                if((n-1)%3==0&&o==1)
                {
                    cout<<"No"<<endl;
                    continue;
                }
                else if(n%3==0&&o==1&&a[n-1]!=1)
                {
                    cout<<"No"<<endl;
                    continue;
                }
                else
                {
                    cout<<"Yes"<<endl;
                    continue;
                }
            }
        }
    }
    return 0;
}

J - Master of GCD(差分/线段树+快速幂)

题意:
给你一个全是1的数组,每次选一个区间,对区间中所有数进行乘x的操作(x== 2||x ==3),问你最后所有数的gcd是多少(对998244353取模)。
思路:

  • 线段树维护区间加法,
    • 最后看大区间里最少的2和3的个数,这就是所有数共有的因子,把它算出来就是gcd了,
  • 差分维护两个数组
    • 一个数组记录2的个数,一个记录3的个数,差分数组还原之后就找两个最小值。
      代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod=998244353;

ll qpow(ll a,ll b)
{
    ll ans=1;
    a%=mod;
    while(b)
    {
        if(b&1)
            ans=ans*a%mod;
        b>>=1;
        a=a*a%mod;
    }
    return ans;
}
int main()
{

    int t;
     scanf("%d",&t);

  while (t--)
  {

       int  n,m;
         scanf("%d%d",&n,&m);
       ll a[n+2]={0};
       ll b[n+2]={0};
       ll i;
       int l,r,x;
       for(i=0;i<m;i++)
       {
             scanf("%d%d%d",&l,&r,&x);
         if(x==2)
         {
             a[l]++; //差分操作
             a[r+1]--; //差分操作
         }
         else
         {
             b[l]++; //差分操作
             b[r+1]--; //差分操作
         }
         }

         ll mia=1e18;
         ll mib=1e18;
         for(i=1;i<=n;i++)
         {
             a[i]+=a[i-1];
             b[i]+=b[i-1];
             mia=min(mia,a[i]);//遍历取最小值
             mib=min(mib,b[i]);//遍历取最小值
         }

         printf("%lld\n",qpow(2,mia)*qpow(3,mib)%mod);

  }
    return 0;
}
posted @ 2021-09-12 10:37  kingwzun  阅读(38)  评论(0编辑  收藏  举报