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("\n");
    }
    return 0;
}

K. K-Bag

我们将序列划分为三段,注意某一段可能为\(0\)
首先把\(k\geq 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 << "]\n";}
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;
}
posted @ 2020-07-28 11:15  heyuhhh  阅读(339)  评论(0编辑  收藏  举报