zoukankan      html  css  js  c++  java
  • 2020牛客暑期多校训练营(第六场)

    Contest Info


    传送门

    Solved A B C D E F G H I J K
    7 / 13 O O O - O - - O - O O
    • O 在比赛中通过
    • Ø 赛后通过
    • ! 尝试了但是失败了
    • - 没有尝试

    Solutions


    A. African Sort

    题意:
    给定一个排列,每次选择一个子序列随机对他们进行排序。
    问最后使得这个排列为(1,2,...,n)的期望次数为多少。

    思路:
    是个假题。。说一下AC的思路吧。
    比较直觉的想法是,每次对一个环进行操作最优。那么操作一个环过后就会产生若干个环。
    定义(f(i))表示将长度为(i)的环归位的期望次数,那么考虑对这个环进行操作的所有情况,直接枚举所有情况环的拆分比较困难,所以就考虑每个长度的环的贡献。

    • 对于一个长度为(n)的排列,其全排列中产生大小为(i)的环的个数为(frac{n!}{i})

    那么根据上式推一推就好了。

    B. Binary Vector

    线性代数题,每次会有(2^n-2^i)个线性无关的,然后推一推就好了。

    C. Combination of Physics and Maths

    每次选择一列最优,所以直接枚举即可。
    容易证明选择多列不如选择一列优。

    E. Easy Construction

    (n)为奇数,则类似({n,1,n-1,2,n-2,cdots})构造即可。
    (n)为偶数,则类似({n,n/2,1,n-1,2,n-2,cdots})构造即可。

    H. Harmony Pairs

    数位dp模板题...

    Code
    #include<bits/stdc++.h>
     
    using namespace std;
     
    #define fi first
    #define se second
    #define mp make_pair
    #define pb push_back
    #define LC k<<1
    #define RC k<<1|1
     
    typedef long long LL;
    const int N=110;
    const int M=1100000;
    const LL mod=1e9+7;
    LL dp[110][2][2][2100];
     
    char s[N];
    int a[N],n;
    LL ans;
    LL dfs(int len,int cur,int less,int delta)
    {
        if (len==0)
        {
            if (delta<1000) dp[len][cur][less][delta]=1;
            else dp[len][cur][less][delta]=0;
            return dp[len][cur][less][delta];
        }
        if (dp[len][cur][less][delta]!=-1) return dp[len][cur][less][delta];
        LL res=0;
        for (int i=0;i<10;i++)
        {
            if (cur&&i>a[len]) break;
            for (int j=0;j<10;j++)
            {
                if (less==0&&j>i) break;
                int ncur=(cur&&i==a[len]);
                int nless=less||(j<i);
                res=(res+dfs(len-1,ncur,nless,delta+i-j))%mod;
            }
        }
        return dp[len][cur][less][delta]=res;
    }
    int main()
    {
        memset(dp,-1,sizeof(dp));
        scanf("%s",s+1);
        n=strlen(s+1);
        reverse(s+1,s+1+n);
        for (int i=1;i<=n;i++)
            a[i]=s[i]-'0';
        ans=dfs(n,1,0,1000);
        cout<<ans<<endl;
        return 0;
    }
    

    J. Josephus Transform

    通过线段树/树状数组求出初始排列,然后直接快速幂即可。
    后面也有(O(n))的做法,就先求出环然后直接算。

    Code
    #include<bits/stdc++.h>
     
    using namespace std;
     
    #define fi first
    #define se second
    #define mp make_pair
    #define pb push_back
    #define LC k<<1
    #define RC k<<1|1
     
    typedef unsigned long long LL;
    const int N=110000;
    const int M=1100000;
     
    int n,m;
    int a[N],b[N],sum[M],c[N];
    void build(int k,int l,int r)
    {
        if (l==r)
        {
            sum[k]=1;
            return;
        }
        int mid=(l+r)/2;
        build(LC,l,mid);
        build(RC,mid+1,r);
        sum[k]=sum[LC]+sum[RC];
    }
    int pre[N],nxt[N];
    int find(int k,int l,int r,int x)
    {
        if (l==r) return 1;
        int mid=(l+r)/2;
        if (x<=mid) return find(LC,l,mid,x);
        else return sum[LC]+find(RC,mid+1,r,x);
    }
    void dec(int k,int l,int r,int x)
    {
        if (l==r)
        {
            sum[k]--;
            return;
        }
        int mid=(l+r)/2;
        if (x<=mid) dec(LC,l,mid,x);
        else dec(RC,mid+1,r,x);
        sum[k]=sum[LC]+sum[RC];
    }
    int find2(int k,int l,int r,int x)
    {
        if (l==r) return l;
        int mid=(l+r)/2;
        if (sum[LC]>=x) return find2(LC,l,mid,x);
        else return find2(RC,mid+1,r,x-sum[LC]);
    }
    int pp[N],tmp[N],cp[N];
    int main()
    {
        scanf("%d %d",&n,&m);
        for (int i=1;i<=n;i++)
            a[i]=i;
        while (m--)
        {
            for (int i=1;i<=n;i++)
                b[i]=i,pre[i]=i-1,nxt[i]=i+1;
            nxt[n]=1,pre[1]=n;
            int k,x;
            scanf("%d %d",&k,&x);
            build(1,1,n);
            int cur=1,len=n;
            for (int i=1;i<=n;i++)
            {
                int tmp=(k-1)%len;
                int pos=find(1,1,n,cur);
                int left=len-pos;
                if (tmp<=left) pos=find2(1,1,n,pos+tmp);
                else pos=find2(1,1,n,tmp-left);
                cur=nxt[pos];
                nxt[pre[pos]]=pre[pos];
                pre[nxt[pos]]=nxt[pos];
                b[i]=pos;
                dec(1,1,n,pos);
                len--;
                 
            }
            for (int i=1;i<=n;i++)
                pp[i]=0;
            for (int i=1;i<=n;i++)
            {
                if (pp[i]) continue;
                int now=i,len=0;
                while (!pp[now])
                {
                    tmp[len++]=now;
                    pp[now]=1;
                    now=b[now];
                }
                int pos=x%len;
                int cur=0;
                for (int j=0;j<len;j++)
                    cp[j]=0;
                for (int j=0;j<len;j++)
                {
                    if (!cp[j])
                    {
                        cur=j;
                        cp[cur]=1;
                        while (!cp[(pos+cur)%len])
                        {
                            cp[(pos+cur)%len]=1;
                            int x=tmp[cur],y=tmp[(pos+cur)%len];
                            swap(a[x],a[y]);
                            cur=(cur+pos)%len;
                        }
                    }
                }
            }
        }
         
        for (int i=1;i<=n;i++)
        {
            printf("%d",a[i]);
            if (i!=n) printf(" ");
            else printf("
    ");
        }
        return 0;
    }
    

    K. K-Bag

    我们将序列划分为三段,注意某一段可能为(0)
    首先把(kgeq n)的情况判掉,之后注意到枚举起点只可能有(O(k))个位置,那么通过hash(O(1))判断一个区间里是否存在(1)~(k)即可。
    算法总的时间复杂度为(O(nlogn))的,瓶颈在于预处理。

    Code
    // Author : heyuhhh
    // Created Time : 2020/07/27 13:24:29
    #include<bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define pb push_back
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    void err(int x) {cerr << x;}
    void err(long long x) {cerr << x;}
    void err(double x) {cerr << x;}
    void err(char x) {cerr << '"' << x << '"';}
    void err(const string &x) {cerr << '"' << x << '"';}
    void _print() {cerr << "]
    ";}
    template<typename T, typename V>
      void err(const pair<T, V> &x) {cerr << '{'; err(x.first); cerr << ','; err(x.second); cerr << '}';}
    template<typename T>
      void err(const T &x) {int f = 0; cerr << '{'; for (auto &i: x) cerr << (f++ ? "," : ""), err(i); cerr << "}";}
    template <typename T, typename... V>
      void _print(T t, V... v) {err(t); if (sizeof...(v)) cerr << ", "; _print(v...);}
    #ifdef Local
    #define dbg(x...) cerr << "[" << #x << "] = ["; _print(x)
    #else
    #define dbg(x...)
    #endif
    //head
    const int N = 5e5 + 5;
    const int P[] = {998244353};
    
    #define ull unsigned long long
    #define rep(ii,a,b) for(int ii=a;ii<=b;++ii)
    #define forn(i, n) for(int i = 0; i < n; ++i)
    #define for1(i, n) for(int i = 1; i <= n; ++i)
    #define FI(n) FastIO::read(n)
    #define FO(n) FastIO::write(n)
    #define Flush FastIO::Fflush()
    namespace FastIO {
    	const int SIZE = 1 << 16;
    	char buf[SIZE], obuf[SIZE], str[60];
    	int bi = SIZE, bn = SIZE, opt;
    	double D[] = {0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001, 0.0000001, 0.00000001, 0.000000001, 0.0000000001};
    	int read(char *s) {
    		while (bn) {
    			for (; bi < bn && buf[bi] <= ' '; bi++);
    			if (bi < bn) break;
    			bn = fread(buf, 1, SIZE, stdin);
    			bi = 0;
    		}
    		int sn = 0;
    		while (bn) {
    			for (; bi < bn && buf[bi] > ' '; bi++) s[sn++] = buf[bi];
    			if (bi < bn) break;
    			bn = fread(buf, 1, SIZE, stdin);
    			bi = 0;
    		}
    		s[sn] = 0;
    		return sn;
    	}
    	bool read(int& x) {
    		int n = read(str), bf = 0;
    		if (!n) return 0;
    		int i = 0; if (str[i] == '-') bf = 1, i++; else if (str[i] == '+') i++;
    		for (x = 0; i < n; i++) x = x * 10 + str[i] - '0';
    		if (bf) x = -x;
    		return 1;
    	}
    	bool read(long long& x) {
    		int n = read(str), bf;
    		if (!n) return 0;
    		int i = 0; if (str[i] == '-') bf = -1, i++; else bf = 1;
    		for (x = 0; i < n; i++) x = x * 10 + str[i] - '0';
    		if (bf < 0) x = -x;
    		return 1;
    	}
    	void write(int x) {
    		if (x == 0) obuf[opt++] = '0';
    		else {
    			if (x < 0) obuf[opt++] = '-', x = -x;
    			int sn = 0;
    			while (x) str[sn++] = x % 10 + '0', x /= 10;
    			for (int i = sn - 1; i >= 0; i--) obuf[opt++] = str[i];
    		}
    		if (opt >= (SIZE >> 1)) {
    			fwrite(obuf, 1, opt, stdout);
    			opt = 0;
    		}
    	}
    	void write(long long x) {
    		if (x == 0) obuf[opt++] = '0';
    		else {
    			if (x < 0) obuf[opt++] = '-', x = -x;
    			int sn = 0;
    			while (x) str[sn++] = x % 10 + '0', x /= 10;
    			for (int i = sn - 1; i >= 0; i--) obuf[opt++] = str[i];
    		}
    		if (opt >= (SIZE >> 1)) {
    			fwrite(obuf, 1, opt, stdout);
    			opt = 0;
    		}
    	}
    	void write(unsigned long long x) {
    		if (x == 0) obuf[opt++] = '0';
    		else {
    			int sn = 0;
    			while (x) str[sn++] = x % 10 + '0', x /= 10;
    			for (int i = sn - 1; i >= 0; i--) obuf[opt++] = str[i];
    		}
    		if (opt >= (SIZE >> 1)) {
    			fwrite(obuf, 1, opt, stdout);
    			opt = 0;
    		}
    	}
    	void write(char x) {
    		obuf[opt++] = x;
    		if (opt >= (SIZE >> 1)) {
    			fwrite(obuf, 1, opt, stdout);
    			opt = 0;
    		}
    	}
    	void Fflush() { if (opt) fwrite(obuf, 1, opt, stdout); opt = 0;}
    };
    
    const int maxsz = 3e5 + 7;//@maxsz素数表@
    //1e7+19,2e7+3,3e7+23,4e5+9 @maxsz最好为素数@
    //1e6+3,2e6+3,3e6+7,4e6+9,1e5+3,2e5+3,3e5+7
    //@要保证取值的操作值集合小于maxsz,@
    //@count操作不增加新节点@
    template<typename key,typename val>
    class hash_map{public:
      struct node{key u;val v;int next;};
      vector<node> e;
      int head[maxsz],nume,numk,id[maxsz];
      bool count(key u){
        int hs=(u%maxsz + maxsz) % maxsz;
        for(int i=head[hs];i;i=e[i].next)
          if(e[i].u==u) return 1;
        return 0;
      }
      val& operator[](key u){
        int hs=(u%maxsz + maxsz) % maxsz;
        for(int i=head[hs];i;i=e[i].next)
          if(e[i].u==u) return e[i].v;
        if(!head[hs])id[++numk]=hs;
        if(++nume>=e.size())e.resize(nume<<1);
        return e[nume]=(node){u,0,head[hs]},head[hs]=nume,e[nume].v;
      }
      void clear(){
        rep(i,0,numk)head[id[i]]=0;
        numk=nume=0;
      }
    };
    hash_map<int, int> mp;
    
    int qpow(ll a, ll b, int op) {
        int MOD = P[op];
        ll res = 1;
        while(b) {
            if (b & 1) res = res * a % MOD;
            a = a * a % MOD;
            b >>= 1;
        }
        return res;
    }
    
    void add(int& a, int b, int op) {
        a += b;
        if (a >= P[op]) a -= P[op];
    }
    
    int n, k;
    int a[N];
    int val[N][1], chkv[1], sum[N][1], vpow[N][1];
    
    void init() {
        for (int i = 1; i < N; i++) {
            for (int j = 0; j < 1; j++) {
                vpow[i][j] = qpow(i, P[j], j);
            }
        }
    }
    
    void run() {
        FI(n), FI(k);
        for (int i = 1; i <= n; i++) {
            FI(a[i]);
        }
        int lb = -1, rb = -1;
        mp.clear();
        for (int i = 1; i <= n; i++) {
            if (mp.count(a[i]) == 0) {
                ++mp[a[i]];
            } else {
                lb = i;
                break;
            }
        }
        mp.clear();
        for (int i = n; i >= 1; i--) {
            if (mp.count(a[i]) == 0) {
                ++mp[a[i]];
            } else {
                rb = i;
                break;
            }
        }
        if (k > n) {
            if (lb == -1) {
                puts("YES");
            } else {
                if (rb >= lb) {
                    puts("NO");
                } else {
                    puts("YES");
                }
            }
            return;
        }
    
        for (int j = 0; j < 1; j++) {
            int tmp = 0;
            for (int i = 1; i <= k; i++) {
                add(tmp, vpow[i][j], j);
            }
            chkv[j] = tmp;
            for (int i = 1; i <= n; i++) {
                val[i][j] = vpow[a[i]][j];
                sum[i][j] = (sum[i - 1][j] + val[i][j]) % P[j];
            }
        }
    
        auto query = [&](int l, int r, int op) {
            return (sum[r][op] - sum[l - 1][op] + P[op]) % P[op];
        };
        for (int l = 1; l <= k; l++) {
            int i;
            bool flag = true;
            for (i = l; i + k - 1 <= n; i += k) {
                bool ok = true;
                for (int j = 0; j < 1; j++) {
                    if (query(i, i + k - 1, j) != chkv[j]) {
                        ok = false;
                        break;
                    }
                }
                if (!ok) {
                    flag = false;
                    break;
                }
            }
            if (flag) {
                if (lb == -1 || (lb >= l && rb <= i)) {
                    puts("YES");
                    return;
                }
            }
        }
        puts("NO");
    }
    int main() {
    #ifdef Local
        freopen("input.in", "r", stdin);
    #endif
        init();
        int T; FI(T); while(T--)
        run();
        Flush;
        return 0;
    }
    
  • 相关阅读:
    Java内存模型
    如何使用原生的Ribbon
    家穷应该读大学吗?| 寒门学子的奋斗史(一)
    试用期没过,因在公司上了1024网站。。。
    两个"�"="锟斤拷"?
    Java字符类Character字符串类String和StringBuffer
    Python抽象基类的定义与使用
    Java数字类Number和Math
    ESP8266 NodeMCU手把手入门(实操篇)——读取传感器的值
    不下软件,照样可以完美正确格式化树莓派SD卡!(恢复U盘/SD卡到满容量)
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/13390048.html
Copyright © 2011-2022 走看看