• 2020牛客多校第六场K.K-Bag (思维?)


    https://ac.nowcoder.com/acm/contest/5671/K

    题意:

    一个序列被称为k-bag,当且仅当它以一些(可能是一个)1~k的排列时。例如,1,2,3,2,1,3,3,2,1是有效的3-bag序列。部分k-bag序列是指k-bag的连续子序列。

    给出长度为n的序列,判断该序列是否为部分k-bag序列。

    思路:

    用一个b数组代表以i结尾的前k个字符是否有重复的,(下标小于k的前面的数字默认不同)没有重复为1,有重复数字为0;

    从后往前找第一个重复数字的位置为top,从这个位置扩k位,如果top+k-1>n,那么 (n , top+k-1)之间的b数组的值为0;

    下标用i表示,i%k的位置代表从 i%k 这个位置开始后面是完整的,如果b[i%k]=0,那么就不能从这个位置开始,如果这样的位置大于等于k,代表不能从前面k个数开始,就不合法。

    所以:下标%k的位置为0的个数(相同位置不能重复计算)大于等于k,则不合法。

     

     当n<k(k很大时,不能往后补位),只会是一个不完整的部分或者两个不完整的部分,则从后往前找到第一个重复数字的位置,判断前面的数字是否重复。

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    const long long mod=1e9+7;
    typedef long long ll;
    const int inf=0x3f3f3f3f;
    const long long INF=0x3f3f3f3f3f3f3f3f;
    const int MAXN=1e6+5;
    const double eps=-1e8;
    typedef pair<int,int>pii;
    int a[MAXN],b[MAXN];
    int vis[MAXN];
    unordered_map<int,int>mp;//map会超时
    int main()
    {
    
        int T;
        scanf("%d",&T);
        while(T--)
        {
            mp.clear();
            int n,k;
            scanf("%d%d",&n,&k);
            int flag=0;
    
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&a[i]);
                if(a[i]>k)flag=1;
    
            }
            for(int i=0;i<=2*n+2;i++)b[i]=1,vis[i]=0;
    
            if(flag)
            {
                printf("NO
    ");
                continue;
            }
            int cnt=0;
            flag=0;
            for(int i=1,j=1;i<=n;i++)//判断以i结尾的前k个数字是否重复
            {
                if(mp[a[i]]==0)cnt++;
                mp[a[i]]++;
                if(i>k)
                {
                    if(mp[a[i-k]]==1)cnt--;
                    mp[a[i-k]]--;
                }
                if(cnt!=k)b[i]=0;
                if(mp[a[i]]==2)flag=1;
                if(flag==0)b[i]=1;
            }
            mp.clear();
    
            int top=-1;
            for(int i=n;i>=1;i--)//从后往前第一个重复数字的位置
            {
                mp[a[i]]++;
                if(mp[a[i]]==2)
                {
                    top=i;
                    break;
                }
            }
            if(n>k)
            {
                cnt=0;
                if(top!=-1)
                {
                    for(int i=n+1;i<top+k;i++)
                    {
                        b[i]=0;
                    }
                }
    
                for(int i=1;i<=2*n+1;i++)
                {
                    if(b[i]==0&&vis[i%k]==0)
                    {
                        cnt++;
                        vis[i%k]=1;
                    }
                }
                if(cnt<k)printf("YES
    ");
                else printf("NO
    ");
            }
            else  //n<k 后一段无重复数字,判断前半段是否有重复数字
            {
                flag=0;
                mp.clear();
                for(int i=1;i<=top;i++)
                {
                    mp[a[i]]++;
                    if(mp[a[i]]>1){flag=1;break;}
                }
                if(flag)printf("NO
    ");
                else printf("YES
    ");
            }
        }
    
        return 0;
    }
    
    /*
    10
    4 6
    1 2 3 3
    4 6
    1 6 6 1
    7 8
    1 2 3 3 4 5 6
    7 8
    1 2 3 3 2 1 1
    7 8
    1 2 3 3 2 1 4
    7 4
    4 4 4 3 2 1 4
    
    */
    View Code
  • 相关阅读:
    SharedPreferences.Editor 的apply()与commit()方法的区别
    Android 解决方法数 65536 (65k) 限制
    Android RatingBar 自定义样式
    自定义 checkbox 新玩法 ?
    Android 透明度百分比对应的 十六进制
    Linux文件权限rwx简单了解
    Linux学习之Vim使用
    Linux学习之用户管理
    Linux学习之sudo命令
    一元稀疏多项式加法运算
  • 原文地址:https://www.cnblogs.com/MZRONG/p/13397535.html
Copyright © 2020-2023  润新知