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;
    }
    
  • 相关阅读:
    如何通过命令行窗口查看sqlite数据库文件
    eclipse自动补全的设置
    文本装饰
    注释和特殊符号
    文本装饰
    网页背景
    通过ArcGIS Server admin 查看和删除已注册的 Web Adaptor
    通过 ArcGIS Server Manager 查看已安装的 Web Adaptor
    通过 ArcGIS Server Manager 验证 DataStore
    Windows上安装ArcGIS Enterprise——以 Windows Server 2012 R2上安装 ArcGIS 10.8为例
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/13390048.html
Copyright © 2011-2022 走看看