Codeforces Round #729 (Div. 2)题解

Codeforces Round #729 (Div. 2)

A - Odd Set

思路:理解了题意基本上就能做了,模拟一下。

\(Code\)

/* -*- encoding: utf-8 -*-
'''
@File    :   F.cpp
@Time    :   2021/07/02 08:32:34
@Author  :   puddle_jumper
@Version :   1.0
@Contact :   1194446133@qq.com
'''

# here put the import lib*/
#include<set>
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<map>
#include<algorithm>
#include<vector>
#include<queue>
#define ch() getchar()
#define pc(x) putchar(x)
#include<stack>
#include<unordered_map>
#define rep(i,a,b) for(auto i=a;i<=b;++i)
#define bep(i,a,b) for(auto i=a;i>=b;--i)
#define lowbit(x) x&(-x)
#define ll long long
#define ull unsigned long long
#define pb push_back
#define mp make_pair
#define PI acos(-1)
using namespace std;
template<typename T>void read(T&x){
	static char c;
	static int f;
	for(c=ch(),f=1; c<'0'||c>'9'; c=ch())if(c=='-')f=-f;
	for(x=0; c>='0'&&c<='9'; c=ch())x=x*10+(c&15);
	x*=f;
}
template<typename T>void write(T x){
	static char q[65];
	int cnt=0;
	if(x<0)pc('-'),x=-x;
	q[++cnt]=x%10,x/=10;
	while(x)
		q[++cnt]=x%10,x/=10;
	while(cnt)pc(q[cnt--]+'0');
}


const int N = 2e5+10;
int _,n;
void solve(){
	read(_);
	while(_--){
        read(n);
        int cnt=0;
        rep(i,1,2*n){
            int x;
            read(x);
            if(x%2)cnt++;
        }
        if(cnt == n)puts("Yes");
        else puts("No");
	}
}


signed main(){solve();return 0; }

B - Plus and Multiply

思路:贪心,我们发现,一个数如果在集合中,那么一定能表示成 \(a^k + pb\)的形式。直接枚举指数 \(k\)

\(Code\)

/* -*- encoding: utf-8 -*-
'''
@File    :   F.cpp
@Time    :   2021/07/02 08:32:34
@Author  :   puddle_jumper
@Version :   1.0
@Contact :   1194446133@qq.com
'''

# here put the import lib*/
#include<set>
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<map>
#include<algorithm>
#include<vector>
#include<queue>
#define ch() getchar()
#define pc(x) putchar(x)
#include<stack>
#include<unordered_map>
#define rep(i,a,b) for(auto i=a;i<=b;++i)
#define bep(i,a,b) for(auto i=a;i>=b;--i)
#define lowbit(x) x&(-x)
#define ll long long
#define ull unsigned long long
#define pb push_back
#define mp make_pair
#define PI acos(-1)
using namespace std;
template<typename T>void read(T&x)
{
    static char c;
    static int f;
    for(c=ch(),f=1; c<'0'||c>'9'; c=ch())if(c=='-')f=-f;
    for(x=0; c>='0'&&c<='9'; c=ch())x=x*10+(c&15);
    x*=f;
}
template<typename T>void write(T x)
{
    static char q[65];
    int cnt=0;
    if(x<0)pc('-'),x=-x;
    q[++cnt]=x%10,x/=10;
    while(x)
        q[++cnt]=x%10,x/=10;
    while(cnt)pc(q[cnt--]+'0');
}


const int N = 2e5+10;
const ll mod = 998244353;
int _,n;
map<ll,pair<ll,ll> > S;
vector<ll>G;
map<ll,ll>cnt;
void solve()
{
    scanf("%d", &_);

    while (_--)
    {
        ll cnts, x, y;
        scanf("%lld%lld%lld", &cnts, &x, &y);

        if (x == 1)
        {   
            if (!((cnts - 1) % y))
            {
                puts("Yes");
            }
            else puts("No");

        }
        else
        {
            bool flag = false;
            ll cur = 1ll;
            while (cur <= cnts)
            {
                if ((cnts - cur) % y == 0)
                {
                    flag = true;
                    break;
                }
                cur = cur * x;
            }
            if (flag) puts("Yes");
            else puts("No");
        }
    }
}


signed main()
{
    solve();
    return 0;
}

C - Strange Function

思路:枚举答案,我们从 \(2\) 开始枚举答案,算一下在范围\([1,n]\)里,答案为 \(2\) 的共有多少个,然后再算答案为 \(3\) 的,答案为 \(4\) 的,现在我们假设算到答案为 \(k\) ,我们看一下如何求出范围在 \([1,n]\) 里且答案为 \(k\) 的数有多少个。设一个从一开始就维护的前缀 \(now\),这个前缀是代表我们算到答案为 \(k\) **这个数的因数中一定要有 \(now\) ** 且 \(now\) 一定是最小的满足条件的那一个。那么我们先假设我们知道了 \(now\) 该怎么计算当前的答案。我们发现 \(cnt1=\lfloor \frac{n}{now} \rfloor\) 代表在 \([1,n]\) 范围里以 \(now\) 为因子的个数,但这并不是答案,因为他可能满足被当前的 \(now\) 整除的前提下,被下一个 \(now\) 也整除,这就会导致答案计算重复,所以我们要减去一个在 \([1,cnt1]\) 中且能被下一个 \(now\) 整除的。我们发现,假如我们设 \(gcd(now,k)=1\)时,那么在 \([1,cnt1]\) 中只要不被 \(k\) 整除就可以了,我们发现在 \(1[1,cnt1]\) 中被 \(k\) 整除的数有 \(cnt2 = \lfloor \frac{cnt1}{k} \rfloor\) 个,所以答案为 \(k\) 的个数就是 \(cnt1-cnt2\) 。那么我们考虑如果 \(gcd(now,k) \neq 1\) 时答案。\(gcd(now,k) \neq 1\) 我们可以将 \(k\) 变为 \(\frac{k}{gcd(now,k)}\) 这样一来,\(gcd\)就变为 \(1\) 了。

还有一个问题是 \(now\) 的转移,和刚才那个操作很像,设当前进行枚举的答案是 \(val\) ,那么 \(now = \frac{now*val}{gcd(now,val)}\) 就是 \(lcm(now,val)\)

可以发现枚举答案的话每一次转移是 \(O(1)\) 然后最大答案不超过 \(50\) 的样子。

\(Code:\)

/* -*- encoding: utf-8 -*-
'''
@File    :   C.cpp
@Time    :   2021/07/05 11:00:31
@Author  :   puddle_jumper 
@Version :   1.0
@Contact :   1194446133@qq.com
'''

# here put the import lib*/
#include<set>
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<map>
#include<algorithm>
#include<vector>
#include<queue>
#define ch() getchar()
#define pc(x) putchar(x)
#include<stack>
#include<unordered_map>
#define rep(i,a,b) for(auto i=a;i<=b;++i)
#define bep(i,a,b) for(auto i=a;i>=b;--i)
#define lowbit(x) x&(-x)
#define ll long long
#define ull unsigned long long
#define pb push_back
#define mp make_pair
#define PI acos(-1)
using namespace std;
template<typename T>void read(T&x){
	static char c;
	static int f;
	for(c=ch(),f=1; c<'0'||c>'9'; c=ch())if(c=='-')f=-f;
	for(x=0; c>='0'&&c<='9'; c=ch())x=x*10+(c&15);
	x*=f;
}
template<typename T>void write(T x){
	static char q[65];
	int cnt=0;
	if(x<0)pc('-'),x=-x;
	q[++cnt]=x%10,x/=10;
	while(x)
		q[++cnt]=x%10,x/=10;
	while(cnt)pc(q[cnt--]+'0');
}
const ll mod = 1e9+7;
int _;
ll x;
ll qpow(ll a,ll b){
	ll res = 1ll;
	while(b){
		if(b&1){res *= a;res %= mod; }
		b>>=1;
		a*=a;
		a%=mod;
	}
	return res ;
}
ll inv(ll a){
	return qpow(a,mod-2);
}
void solve(){
	read(_);
	while(_--){
		read(x);
		ll now = 1ll;
		ll id = 2ll;
		ll ans = 0ll;
	//	一个数x,y
	//	ll cnt = 0ll;
		while(now <= x){
			ll k = x/now;
			ll f = __gcd(now,id);
			ll p = id / f;
			ll cnt = k - k/p;
			//printf("%lld %lld %lld %lld\n",id-1,cnt,now,f);
			//cnt += k-k/id;
			//k = (k%mod + mod) %mod;
			ans += cnt * id;
			ans %= mod;
			now *= id/__gcd(now,id);

			//now *= id;
			
			id++;

			//id %= mod;
		}
	//	printf("%lld \n",now);
		write(ans);pc('\n');
	}
}

signed main(){solve();return 0;}

D - Priority Queue

思路:我们考虑每一个值在全部集合中能出现多少次,对于每一个 \(a_x\) 进行 \(dp\) (如果是 \(“-”\) 那么设当前 \(a_x = -1\)),设 \(f(i,j)\) 代表当前进行到第 \(i\) 个数,且前面有 \(j\) 个比 \(a_x\) 要小的数。考虑转移:

  • 如果当前 \(a_i = -1\) 的话,那么如果不选当前的 \("-"\) ,有 \(f(i-1,j)\) 种方案,如果选择当前的\("-"\) 那么有$ f(i-1,j+1)$ 种方案数 ,特别的,如果 \(j = 0\)\(i < x\) 再额外加上一个 \(f(i-1,j)\) ,这个可以这样理解,当 \(j=0\)\(i<x\) 时,我们选择当前的 \("-"\)\(f(i-1,j)\) 中包括的方案数中,可以根据空集和非空集将他们分为两种,我们先看空集,如果当前为空集的话,\(”-“\) 并不会影响什么,\(f(i-1,j)\) 的空集部分是可以算进 \(f(i,j)\) 内的,那么我们看如果当前为非空集的话,又因为 \(i<x\) ,所以减掉一个比 \(a_x\) 大的数并没有影响 \(a_x\) 的贡献,所以 \(f(i-1,j)\) 的非空集部分也是可以算进 \(f(i,j)\) 内。这样就是为什么再加一遍 \(f(i-1,j)\) 的原因。
  • 如果当前 \(a_i > a_x\)\(f(i,j) = f(i-1,j)*2\) 。分为选和不选两种方案,都是 \(f(i-1,j)\) 种 。
  • 如果当前\(a_i<a_x\)\(f(i,j) = f(i-1,j-1) + f(i-1,j)\) ,选的话是只需要满足前面有 \(j-1\) 个比他小的数。
  • 如果当前\(a_i = a_x\)
    • \((1)\) 如果\(i >x\) ,那么将 \(a_i\) 看成比 \(a_x\) 大的数。
    • (2)否则将 \(a_i\) 看成比\(a_x\) 小的数。
    • 这一步是通过字典序去重,因为如果有多个相同的数,可以取任意一个,我们不妨设定为每次取下标最小的一个,越靠后的数越大。

如果还有什么不懂的地方,看代码:

\(Code:\)

/* -*- encoding: utf-8 -*-
'''
@File    :   D.cpp
@Time    :   2021/07/06 10:09:22
@Author  :   puddle_jumper 
@Version :   1.0
@Contact :   1194446133@qq.com
'''

# here put the import lib*/
#include<set>
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<map>
#include<algorithm>
#include<vector>
#include<queue>
#define ch() getchar()
#define pc(x) putchar(x)
#include<stack>
#include<unordered_map>
#define rep(i,a,b) for(auto i=a;i<=b;++i)
#define bep(i,a,b) for(auto i=a;i>=b;--i)
#define lowbit(x) x&(-x)
#define ll long long
#define ull unsigned long long
#define pb push_back
#define mp make_pair
#define PI acos(-1)
using namespace std;
template<typename T>void read(T&x){
	static char c;
	static int f;
	for(c=ch(),f=1; c<'0'||c>'9'; c=ch())if(c=='-')f=-f;
	for(x=0; c>='0'&&c<='9'; c=ch())x=x*10+(c&15);
	x*=f;
}
template<typename T>void write(T x){
	static char q[65];
	int cnt=0;
	if(x<0)pc('-'),x=-x;
	q[++cnt]=x%10,x/=10;
	while(x)
		q[++cnt]=x%10,x/=10;
	while(cnt)pc(q[cnt--]+'0');
}
const int N = 5e2+10;
const ll mod = 998244353;
int n;
ll a[N],f[N][N];
ll work(){
	ll ans = 0ll;
	rep(i,1,n){
		if(a[i] == -1)continue;
		memset(f,0,sizeof f);
		f[0][0] = 1;
		rep(p,1,n){
			if(p == i){memcpy(f[p],f[p-1],sizeof f[p-1]); continue;}
			rep(k,0,p){
				if(a[p] > 0){
					ll c = 0;if(k-1>=0)c = f[p-1][k-1];
					if(a[p] > a[i])f[p][k] = (f[p-1][k]*2ll)%mod;
					else if(a[p]<a[i] or p<i)f[p][k] = (c + f[p-1][k])%mod;//选的小,那么能当替死鬼
					else f[p][k] = (f[p-1][k]*2ll)%mod;
				} else {
					f[p][k] = (f[p-1][k+1] + f[p-1][k])%mod;
					if(!k and p<i)(f[p][k] += f[p-1][k])%mod;
				}
			}
		}
		ll sum = 0ll;
		rep(j,0,n)sum = (sum + f[n][j])%mod;
		ans += sum * a[i];
		ans %= mod;
	}
	return ans;
}
void solve(){
	read(n);
	rep(i,1,n){
		char op[3];
		scanf("%s",op);
		if(*op == '-'){
			a[i] = -1;
		
		} else {
			read(a[i]);
		}
	}
	write(work());pc('\n');
}

signed main(){solve();return 0;}





E1 - Abnormal Permutation Pairs (easy version)

思路:对于字典序的题目,我们可以枚举前面相同的位数来进行 \(dp\)。我们设前 \(x-1\) 位相同。 且设 \(i = n-x\) 。因为前\(x-1\) 位相同,所以前 \(x-1\) 位内部的逆序对数相同,并且前 \(x-1\) 位对于后 \(i+1\) 位来说,逆序对数也相同,那么要保证 \(p\) 串逆序对数大于 \(q\) 串,就说明是\(i+1\) 位内部逆序对数 \(p\) 串大于 \(q\) 。设 \(u\)\(p\) 串后 \(i\) 位内部的逆序对数, \(v\)\(q\) 串后 \(i\) 位内部的逆序对数。\(s\)\(p\) 串后第 \(i\) 位对于后面 \(i\) 位的逆序对数, \(t\)\(q\) 串后第 \(i\) 位对于后面 \(i\) 位的逆序对数。有 \(u+s>v+t\) 所以 \(t-s < u-v\) ,对于每一组 \(u,v\) 计算符合要求的 \(t-s\) 的个数,则有

\[\sum_{x=1}^{u-v-1} i+1-x = \frac{i(i+1)}{2} - \frac{(i+1-(u-v))(i+2-(u-v))}{2} \]

\[f(i,u-v) = \frac{i(i+1)}{2} - max(\frac{(i+1-(u-v))(i+2-(u-v))}{2},0) \]

意为对于 \(i\) 位不同且对于 \(1\)\((u,v)\) 所满足的\((s,t)\) 的方案数。我们设 \(dp(i,j)\) 代表长度为 \(i\) 的排列中,逆序对数为 \(j\) 的方案数。可以通过前缀和 \(O(n^3)\) 计算出来。那么对于每对 \((u,v)\) 满足的方案数就是 \(dp_{i,u}dp_{i,v}f(i,u-v)\) ,那么枚举 \((u,v)\) 的总方案数就是

\[\sum_{u=0}^{i(i+1)/2}\sum_{v=0}^{u-1} dp_{i,u}dp_{i,v}f(i,u-v) \]

还得再乘上前面的相同部分:在 \(n\) 位中选择 \(n-i-1\) 位的方案数 \(C^{n-i+1}_{n}\) ,全排列 \(n-i-1\)\((n-i-1)!\) 因此答案是

\[\sum^{n-1}_{i=0}C^{n-i+1}_{n} (n-i-1)!\sum_{u=0}^{i(i+1)/2}\sum_{v=0}^{u-1} dp_{i,u}dp_{i,v}f(i,u-v) \]

复杂度 \(O(n^5)\) 考虑到 \(v<u-i\) 时,\(f(i,u-v) = \frac{i(i+1)}{2}\) 那么可以维护 \(dp_{i,j}\) 的前缀和结合 \(f(i,u-v)\) 达到 \(O(n^4)\)

参考dalao的代码

\(Code:\)

/* -*- encoding: utf-8 -*-
'''
@File    :   E1.cpp
@Time    :   2021/07/06 15:40:33
@Author  :   puddle_jumper 
@Version :   1.0
@Contact :   1194446133@qq.com
'''
# here put the import lib*/
#include<set>
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<map>
#include<algorithm>
#include<vector>
#include<queue>
#define ch() getchar()
#define pc(x) putchar(x)
#include<stack>
#include<unordered_map>
#define rep(i,a,b) for(auto i=a;i<=b;++i)
#define bep(i,a,b) for(auto i=a;i>=b;--i)
#define lowbit(x) x&(-x)
#define ll long long
#define ull unsigned long long
#define pb push_back
#define mp make_pair
#define PI acos(-1)
using namespace std;
template<typename T>void read(T&x){
	static char c;
	static int f;
	for(c=ch(),f=1; c<'0'||c>'9'; c=ch())if(c=='-')f=-f;
	for(x=0; c>='0'&&c<='9'; c=ch())x=x*10+(c&15);
	x*=f;
}
template<typename T>void write(T x){
	static char q[65];
	int cnt=0;
	if(x<0)pc('-'),x=-x;
	q[++cnt]=x%10,x/=10;
	while(x)
		q[++cnt]=x%10,x/=10;
	while(cnt)pc(q[cnt--]+'0');
}
const int N = 55;
#define int long long 
int n;ll mod,f[N][N*N];
ll C[N][N],A[N],sum[N][N*N];
void init(){
	f[1][0] = 1ll;
	rep(i,0ll,N*N)sum[1][i] = 1ll;
	for(int i=2ll;i<=n;i++){
		for(int j=0ll;j<=i*(i-1)/2;j++){
			f[i][j]=sum[i-1][j];
		//	printf("%d %d %d\n",i,j,f[i][j]);
			if(j-i>=0) f[i][j]=(f[i][j]-sum[i-1][j-i]+mod)%mod;
		//	printf("%d %d %d\n",i,j,f[i][j]);
		} sum[i][0]=f[i][0];
		for(int j=1;j<=N*N;j++) sum[i][j]=(sum[i][j-1]+f[i][j])%mod;
	}
	//printf("%lld\n",f[10][5]);
	C[0][0] = 1ll;
	//C[1][1] = C[1][0] = 1ll;
	rep(i,1ll,n){
		rep(j,0ll,i){
			ll now = 0ll;if(j)now = C[i-1][j-1];
			C[i][j] = (C[i-1][j] + now)%mod;
			//printf("%lld\n",C[i][j]);
		}
	}
	A[0] =1ll ;
	rep(i,1ll,n)A[i] = (A[i-1] * i)%mod;
}
int a[N],b[N];


void solve(){
	read(n);read(mod);
	init();
	//枚举前面有几个一样的
	ll ans = 0ll;
	rep(idx,0ll,n-1){
	//	ll idx = n - i;// 后面有idx+1位,
		//枚举u,v
		ll lin = idx*(idx+1)/2;
		ll now = 0ll;
		rep(u,1ll,(idx*(idx-1))/2ll){
			now += (lin%mod*sum[idx][u-1]%mod)%mod*f[idx][u]%mod;
			//printf("%lld %lld %lld\n",idx,u-1,sum[idx][u-1]);
			now %= mod;
			rep(v,max(0ll,u-idx),u-1){
				ll k = ((idx-u+v+1)*(idx-u+v+2)/2%mod*f[idx][v])%mod;
				now = ((now - k*f[idx][u])%mod+mod)%mod;
			}
		}
		ans += (now * C[n][n-idx-1]%mod*A[n-idx-1])%mod;
		ans %= mod;
//		printf("%lld %lld %lld\n",C[n][n-idx-1],A[n-idx-1],);
	}
	write(ans);pc('\n');
}

signed main(){ solve();return 0;}



posted @ 2021-07-07 21:53  xiaodangao  阅读(183)  评论(0编辑  收藏  举报