Codeforces Round #819 (Div. 1 + Div. 2)
\(\texttt{Unrated}\)
好像是印度老哥又一次放了 F 原题,悲。
A
考虑保留头尾的数,\(3\) 种情况的分讨,即保留 \(a_1\),保留 \(a_n\),或者都保留。
My Code
#include<bits/stdc++.h>
#define ll long long
#define inf (1<<30)
#define INF (1ll<<60)
#define pii pair<int,int>
#define mkp make_pair
#define fi first
#define se second
#define all(a) a.begin(),a.end()
#define siz(a) (int)a.size()
#define rep(i,j,k) for(int i=(j);i<=(k);i++)
#define per(i,j,k) for(int i=(j);i>=(k);i--)
#define pt(a) cerr<<#a<<' '<<a<<' '
#define pts(a) cerr<<#a<<' '<<a<<'\n'
//#define int long long
using namespace std;
const int MAXN=2e3+10;
int a[MAXN];
void solve(){
int n;cin>>n;
rep(i,1,n) cin>>a[i];
if(n==1){cout<<0<<'\n';return;}
int mx=0,mn=1000;
rep(i,1,n-1) mn=min(mn,a[i]);
int ans=a[n]-mn;
rep(i,2,n) mx=max(mx,a[i]);
ans=max(ans,mx-a[1]);
rep(i,2,n) ans=max(ans,a[i-1]-a[i]);
cout<<ans<<'\n';
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int T;for(cin>>T;T--;)
solve();
return 0;
}
B
一堆特判就行了。
首先判断 \(n>m\) 无解。然后是如果 \(m\%n=0\),则每个位置平均分就行。
接下来按照 \(1,1,\cdots,m-n+1\) 的方式构造。如果 \(n\) 是奇数,则一定可以。如果是偶数,则判断 \(m\) 是否是奇数,如果是,则无解,否则可以按 \(1,1,\cdots,\dfrac{m-n+2}{2},\dfrac{m-n+2}{2}\) 的方式构造。
My Code
#include<bits/stdc++.h>
#define ll long long
#define inf (1<<30)
#define INF (1ll<<60)
#define pii pair<int,int>
#define mkp make_pair
#define fi first
#define se second
#define all(a) a.begin(),a.end()
#define siz(a) (int)a.size()
#define rep(i,j,k) for(int i=(j);i<=(k);i++)
#define per(i,j,k) for(int i=(j);i>=(k);i--)
#define pt(a) cerr<<#a<<' '<<a<<' '
#define pts(a) cerr<<#a<<' '<<a<<'\n'
#define int long long
using namespace std;
void solve(){
int n,m;cin>>n>>m;
if(n>m){cout<<"No"<<'\n';return;}
if(m%n==0){
cout<<"Yes\n";
rep(i,1,n) cout<<m/n<<' ';cout<<'\n';
return;
}else{
if(n&1){
cout<<"Yes\n";
rep(i,1,n-1) cout<<1<<' ';
cout<<m-(n-1)<<' '<<'\n';
return;
}else{
if(m&1) cout<<"No\n";
else{
cout<<"Yes\n";
rep(i,1,n-2) cout<<1<<' ';
rep(i,1,2) cout<<(m-(n-2))/2<<' ';
return;
}
}
}
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int T;for(cin>>T;T--;)
solve();
return 0;
}
C
比较显然的做法是一个 )(
那么这两个位置在同一个联通块里,匹配的两个也在同一个联通块里。这样用并查集数一下就行了。
更快的做法就是考虑 ((
会出现两个联通块分开,所以答案就是 ((
的个数加一。
My Code
#include<bits/stdc++.h>
#define ll long long
#define inf (1<<30)
#define INF (1ll<<60)
#define pii pair<int,int>
#define mkp make_pair
#define fi first
#define se second
#define all(a) a.begin(),a.end()
#define siz(a) (int)a.size()
#define pb emplace_back
#define rep(i,j,k) for(int i=(j);i<=(k);i++)
#define per(i,j,k) for(int i=(j);i>=(k);i--)
#define pt(a) cerr<<#a<<' '<<a<<' '
#define pts(a) cerr<<#a<<' '<<a<<'\n'
//#define int long long
using namespace std;
const int MAXN=2e5+10;
int f[MAXN];
int find(int x){
while(f[x]^x) x=f[x]=f[f[x]];
return x;
}
void solve(){
int n;string s;cin>>n>>s;
iota(f+1,f+1+2*n,1);
s=' '+s;
vector<int> cur;
rep(i,1,2*n){
if(s[i]=='('){
cur.pb(i);
if(i!=1&&s[i-1]==')') f[find(i-1)]=find(i);
}
else{
f[find(cur.back())]=find(i);
cur.pop_back();
}
}
int ans=0;
rep(i,1,2*n) ans+=(find(i)==i);
cout<<ans<<'\n';
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int T;for(cin>>T;T--;)
solve();
return 0;
}
D
贪心地想,每条边最多使得联通块个数减一,所以我们只要两张图都不成环就行了。具体做法有很多,比较简单的就是先随便找一棵生成树,然后判断剩下的边是否成环,如果成环就任取一条环上的边,并取这条边深度较大的节点,用这个点在生成树上的父亲边替换选取的环上的边。
My Code
#include<bits/stdc++.h>
#define ll long long
#define inf (1<<30)
#define INF (1ll<<60)
#define pii pair<int,int>
#define mkp make_pair
#define fi first
#define se second
#define all(a) a.begin(),a.end()
#define siz(a) (int)a.size()
#define pb emplace_back
#define rep(i,j,k) for(int i=(j);i<=(k);i++)
#define per(i,j,k) for(int i=(j);i>=(k);i--)
#define pt(a) cerr<<#a<<' '<<a<<' '
#define pts(a) cerr<<#a<<' '<<a<<'\n'
//#define int long long
using namespace std;
const int MAXN=2e5+10;
int u[MAXN],v[MAXN],f[MAXN];
int find(int x){
while(x^f[x]) x=f[x]=f[f[x]];
return x;
}
vector<int> e[MAXN];
int fa[MAXN],dep[MAXN];
void dfs(int x){
for(int s:e[x]){
if(s==fa[x]) continue;
fa[s]=x;dep[s]=dep[x]+1;
dfs(s);
}
}
int ans[MAXN],ban[MAXN];
void solve(){
int n,m;cin>>n>>m;
iota(f+1,f+1+n,1);
rep(i,1,m) ans[i]=0;
rep(i,1,n) ban[i]=0,e[i].clear(),fa[i]=dep[i]=0;
rep(i,1,m){
cin>>u[i]>>v[i];
if(find(u[i])==find(v[i])) continue;
f[find(u[i])]=find(v[i]);
ans[i]=1;
e[u[i]].pb(v[i]);
e[v[i]].pb(u[i]);
}
if(m==n+2){
int id;
rep(i,1,m){
if(ans[i]) continue;
id=i;
ban[u[i]]=ban[v[i]]=1;
}
int cnt=0;
rep(i,1,n) cnt+=(ban[i]>0);
if(cnt==3){
dfs(1);
if(dep[u[id]]<dep[v[id]]) swap(u[id],v[id]);
rep(j,1,m){
if(u[j]==u[id]&&v[j]==fa[u[id]])
swap(ans[id],ans[j]);
else if(v[j]==u[id]&&u[j]==fa[u[id]])
swap(ans[id],ans[j]);
}
}
}
rep(i,1,m) cout<<ans[i];cout<<'\n';
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int T;for(cin>>T;T--;)
solve();
return 0;
}
E
考虑一个置换群什么时候能满足题目的条件。首先如果大小小于等于 \(2\) 的置换群,则一定可行。如果大小为 \(4\),则有 \(3,4,2,1\) 或者 \(4,3,1,2\) 两种情况满足,且要求前两个相邻,后两个相邻。大胆猜测没有别的情况了。
所以问题就转化成,对于 \(n\) 个数,要求按如下方式分组的数目:
- 一个数一组;
- 任意两个数一组;
- 相邻的数和另一相邻的数一组,共 \(4\) 个数,且权重为 \(2\)。
考虑到方式 \(3\) 比较困难,所以先看只考虑前两种方式的方案计数,不难发现就是个简单的 \(dp\)。即令 \(dp_{i,0/1}\) 表示 \(i\) 个数,最后一个数是单独一组或者和前面某一个数一组的方案数,不难得到:
然后考虑方式 \(3\),我们可以枚举一个 \(m\) 表示相邻的数的组数,保证 \(m\) 为偶数。那么我们只需要知道,这 \(m\) 个数两两配对的方案数(可以简单 dp,不再赘述)和在 \(n\) 个数中选出这两两相邻的 \(m\) 组的方案数(利用组合数,就是 \(n-m\choose m\))。
那最后直接统计答案就行了。
My Code
#include<bits/stdc++.h>
#define ll long long
#define inf (1<<30)
#define INF (1ll<<60)
#define pii pair<int,int>
#define mkp make_pair
#define fi first
#define se second
#define all(a) a.begin(),a.end()
#define siz(a) (int)a.size()
#define rep(i,j,k) for(int i=(j);i<=(k);i++)
#define per(i,j,k) for(int i=(j);i>=(k);i--)
#define pt(a) cerr<<#a<<' '<<a<<' '
#define pts(a) cerr<<#a<<' '<<a<<'\n'
#define int long long
using namespace std;
const int MOD=998244353;
const int MAXN=3e5+10;
int ksm(int a,int p){
int ret=1;while(p){
if(p&1) ret=ret*a%MOD;
a=a*a%MOD; p>>=1;
}return ret;
}
int inv(int x){return ksm(x,MOD-2);}
int fac[MAXN],ifac[MAXN];
void init(){
fac[0]=ifac[0]=1;
rep(i,1,MAXN-10) fac[i]=fac[i-1]*i%MOD;
ifac[MAXN-10]=inv(fac[MAXN-10]);
per(i,MAXN-11,1) ifac[i]=ifac[i+1]*(i+1)%MOD;
}
int C(int n,int m){return fac[n]*ifac[m]%MOD*ifac[n-m]%MOD;}
int dp[MAXN][2],f[MAXN];
void solve(){
int n;cin>>n;
int ans=0;
for(int m=0;m<=n;m+=2){
if(n-m>=m){
ans=(ans+C(n-m,m)*f[m]%MOD*(dp[n-2*m][0]+dp[n-2*m][1])%MOD*ksm(2,m/2)%MOD)%MOD;
}
}
cout<<ans<<'\n';
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
init();f[0]=1;
for(int i=2;i<=MAXN-10;i+=2)
f[i]=f[i-2]*(i-1)%MOD;
dp[0][0]=1;
rep(i,1,MAXN-10){
dp[i][0]=(dp[i-1][0]+dp[i-1][1])%MOD;
if(i>1) dp[i][1]=(dp[i-2][0]+dp[i-2][1])%MOD*(i-1)%MOD;
}
int T;for(cin>>T;T--;)
solve();
return 0;
}