zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    SQL Server 实现Split函数
    15.java设计模式之访问者模式
    14.java设计模式之命令模式
    13.java设计模式之模板模式
    12.java设计模式之代理模式
    11.java设计模式之享元模式
    10.java设计模式之外观模式
    9.java设计模式之组合模式
    8.java设计模式之装饰者模式
    7.java设计模式之桥接模式
  • 原文地址:https://www.cnblogs.com/MZRONG/p/13397535.html
Copyright © 2011-2022 走看看