CF2134游记
前言
这次比赛打炸了, C 题磕了好久没做出来,后面不想打了,在 \(0:00\)提前离场。
CF2134 \(Div.2\) 难度,场切 A,B 。
A.Painting With Two Colors
题面
共 \(t\) 组数据,每组数据:
给定 \(3\) 个整数 \(n,a,b\)
问你能否选择 \(2\) 个整数 \(x,y\)
将 \(n\) 个格子中第 \(x\) 至 \(x+a-1,y\) 至 \(y+b-1\) 个格子分别染上红色和蓝色,蓝色会覆盖红色。
问最后能否使得这 \(n\) 个格子染色情况对称。
思路
如果 \(a\le b\) 那么只需要考虑 \(b\) 即可
而对称的充要条件是 \(n-b\equiv 0(mod\) \(2)\)
我们只需要令 \(a_i\leftarrow a_i+(a_i\%(k+1))\times k\)
实现
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
int tt,n,a,b;
void solve(){
cin>>n>>a>>b;
if(a>b){
if(((n-a)&1)||((n-b)&1))puts("No");
else puts("Yes");
}
else{
if((n-b)&1)puts("No");
else puts("Yes");
}
}
int main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>tt;
while(tt--)solve();
return 0;
}
B.Add 0 or K
题面
共 \(t\) 组数据,每组数据:
给定一个大小为 \(n\) 的数组 \(a\) ,与一个整数 \(k\) 。
你可以进行至多 \(k\) 次操作:
- 取一个数组 \(b\) ,其中 \(b_i\int\{0,k\}\)
- 令 \(a_i\leftarrow a_i+b_i\)
问你是否能使得 \(gcd(a_1,...,a_n)>1\)
思路
我们注意到最终的 \(a_i\) 共有 \(k+1\) 种取值 \(A_i={a_i,a_i+k,a_i+2k,...a_i+k^2}\)
而 \(gcd(k,k+1)=1\) 所以 \(A_i\equiv{0,1,...,n}(mod\) \(k+1)\)
所以我们一定能在 \(k\) 次操作以内,使得 \(a_i\) 变为 \(k+1\) 的倍数。
而 \(k\equiv-1(mod\) \(k+1)\)
实现
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
#define ll long long
const int N=1e5+5;
int tt,n;ll a[N],k;
void solve(){
cin>>n>>k;
for(int i=1;i<=n;++i)cin>>a[i];
if(n==1){
cout<<a[1]+k<<endl;
}
else{
for(int i=1;i<=n;++i)cout<<a[i]+(a[i]%(k+1))*k<<" ";
cout<<endl;
}
}
int main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>tt;
while(tt--)solve();
return 0;
}
C.Even Larger
题面
定义
对于一个数组 \(a\) ,若其所有大小不小于 \(2\) 的子数组 \(a[l,...,r]\) 都有:
\(\displaystyle \sum_{odd}a_i\le\sum_{even}a_i\)
则称其为可爱数组。
共 \(t\) 组数据,每组数据:
给定一个大小为 \(n\) 数组 \(a\) ,你可以进行若干次操作:
- 若 \(a_i>0\) ,令 \(a_i\leftarrow a_i-1\) 。
问最少进行多少次操作可以使得 \(a\) 变为可爱数组。
思路
首先我们可以发现,我们只需要考虑大小为 \(2,3\) 的子数组,因为更大的子数组可以由若干个大小为 \(2,3\) 的数组组成。
若这些小的子数组为可爱的,则大的数组一定是可爱的。
若 \(n\) 为偶数,我们令 \(n\leftarrow n+1,a_n=0\)
对于所有下标 \(l,r\) 满足:
\(l,r\) 是奇数且 \(l+2=r\) ,如果满足 \(a[l,l+1,r]\) 是可爱的。
则有 \(a_{l+1}\ge a_l+a_r\) 。
进而 \(\displaystyle\sum_{even}a_i\ge\sum_{even}(a_{i-1}+a_{i+1})=2\sum_{odd}a_i-a_1-a_n\ge\sum_{odd}a_i\) 。
那么我我们只需要贪心地从左至右处理对应的 \(l,r\) 即可。
实现
#include<iostream>
using namespace std;
const int N=2e5+10;
int tt,n,a[N],b[N],mn;long long ans;
void solve(){
cin>>n;
ans=0;
for(int i=1;i<=n;++i){
cin>>a[i];
if(i&1)b[i]=0;
}
if(!(n&1)){
++n;
b[n]=a[n]=0;
}
for(int i=1;i<=n;i+=2){
mn=a[i];
if(i>=3)mn=min(mn,a[i-1]-b[i-2]);
if(i<n)mn=min(a[i+1],mn);
b[i]=mn;
ans+=a[i]-mn;
}
cout<<ans<<endl;
}
int main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>tt;
while(tt--)solve();
return 0;
}
D.Sliding Tree
题面
共 \(t\) 组数据,每组数据:
给定一棵大小为 \(n\) 的树,你需要进行若干次操作,使得这棵树变为一个链:
- 选定 \(3\) 个整数 \(a,b,c\) ,
- 将 \(b\) 连接的所有非 \(b,c\) 节点连接到 \(c\) 上。
思路
引理1
对于任意路径 \(l:(u,v)\) 和任意操作 \(a,b,c\) ,路径 \(u,v\) 的长度 \(d(l)\) 会至多增加 \(1\) 。
证明:
若 \(b\notin l\) 或 \(b\in\{u,v\}\)
显然 \(d(l)\) 不会变
否则若 \(b\in l\) :
记 \(l\) 上与 \(b\) 相邻的两个点为 \(p,q\)
- 若 \(a=p,c=q\) ,则 \(d(l)\) 不变;
- 若 \(a=p,c\ne q\) ,则 \(d(l)+1\) ;
- 若 \(a\ne p,c=q\) ,则 \(d(l)-1\) 。
所以 \(d(l)\) 至多增加 \(1\) 。
于是树上最长路径————直径也至多增加 \(1\)
那么我们是否能做到每次都令直径增加 \(1\) 呢?
由引理1种的 \(2.\) 可知:
只需要找到一组点 \(a,b,c\) ,满足 \(a,b\) 在 \(l\) 上而 \(c\) 不在 \(l\) 上即可。
这样的点显然存在,我们只需要输出任意一组。
求直径的两端点用一个 DFS 求出;
标记直径两端点再用一个 DFS ;
最后,使用 DFS 寻找上述点对即可。
实现
#include<iostream>
#include<vector>
using namespace std;
const int N=2e5+5;
int tt,n,dis[N],deg[N];
bool flg,mrk[N];
vector<int>g[N];
void dfs1(int u,int ft){
for(auto v:g[u]){
if(v==ft)continue;
dis[v]=dis[u]+1;
dfs1(v,u);
}
}
void dfs2(int u,int ft){
for(auto v:g[u]){
if(v==ft)continue;
dfs2(v,u);
mrk[u]|=mrk[v];
}
}
bool dfs3(int u,int ft){
for(auto v:g[u]){
if(v==ft)continue;
if(!mrk[v]&&ft){
cout<<ft<<" "<<u<<" "<<v<<endl;
return 1;
}
if(mrk[v])if(dfs3(v,u))return 1;
}
return 0;
}
void solve(){int x,y;
cin>>n;
for(int i=1;i<=n;++i){
deg[i]=mrk[i]=0;
g[i].clear();
}
for(int i=1;i<n;++i){
cin>>x>>y;
++deg[x];++deg[y];
g[x].push_back(y);
g[y].push_back(x);
}
flg=1;
for(int i=1;i<=n;++i)if(deg[i]>2){
flg=0;break;
}
if(flg){
cout<<"-1\n";
return;
}
dis[1]=0;
dfs1(1,0);
y=1;
for(int i=1;i<=n;++i)if(dis[i]>dis[y])y=i;
x=y;
dfs1(y,0);
for(int i=1;i<=n;++i)if(dis[i]>dis[x])x=i;
mrk[x]=1;
dfs2(y,0);
dfs3(y,0);
}
int main(){
cin>>tt;
while(tt--)solve();
return 0;
}
E.Power Boxes
题面
交互题
共 \(t\) 组数据,每组数据:
你需要确定一个未知的大小为 \(n\) 的数组 \(a\) 。
你可以进行至多 \(\left\lceil\frac{3n}{2}\right\rceil\) 次询问:
- \(swap\) \(i\) :交换 \(a_i\) 与 \(a_{i+1}\) ;
- \(throw\) \(i\) :从 \(i\) 开始执行 \(i\leftarrow i+a_i\) 直至 \(i>n\) ,并返回执行次数 \(d_i\) 。
思路
不妨设 \(d_{n+1}=d_{n+2}=0\) 。
首先,若 \(d_{i+1}\ne d{i+2}\) 我们很容易确定 \(a_i\) 。
只需要询问 \(throw\) \(i\) 得到 \(d_{i}\) 即可;
否则 \(d_{i}=d_{i+1}+1\) 不需要询问。
引理1
已确定的 \(a_i\) 有至少 \(\left\lceil\frac{n}{2}\right\rceil\) 个
证明:
若 \(a_i\) 不确定,必有 \(d_{i}=d_{i+1}+1\)
那么 \(a_i-1\) 一定是确定的。
同时 \(d_{i+1}=d_{i+2}\) ,而 \(d_{i+1}=d_{i+1+a_i}+1\) ,
于是有 \(d_{i+2}=d_{i+1}=d_{i+2}+1\) ,即 \(a_{i+1}\) 也是确定的。
于是有: \(tot_{确定}+tot_{不确定}=n\) 且 \(tot_{确定}\ge tot_{不确定}\) 。
即 \(tot_{确定}\ge\left\lceil\frac{n}{2}\right\rceil\) 。
所以对于不确定的 \(a_i\) 我们将其与 \(a_{i+1}\) 交换,
由于 \(d_{(i+1)+1}\ne d_{(i+1)+2}\) 我们可以确定交换过来的 \(a_i\) 。
对于 \(a_n\) 我们将其与 \(a_{n-1}\) 交换并询问 \(throw\) \(n-1\) 即可。
最终询问次数为 \(2\times tot{不确定}+tot_{确定}\le 3\times tot_{确定}\le \left\lceil\frac{3n}{2}\right\rceil\)
实现
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=1005;
int tt,n,d[N],a[N];
void solve(){
cin>>n;
for(int i=1;i<=n;++i)a[i]=0;
d[n]=1;d[n+1]=d[n+2]=0;
for(int i=n-1;i>=1;--i){
if(d[i+1]==d[i+2]){
d[i]=d[i+1]+1;
}
else{
cout<<"throw "<<i<<endl;
cin>>d[i];
if(d[i]==d[i+1]+1)a[i]=1;
else a[i]=2;
}
}
for(int i=1;i<=n;++i)if(!a[i]){
if(i==n){
cout<<"swap "<<n-1<<"\nthrow "<<n-1<<endl;
cin>>a[n];
if(a[n]==2)a[n]=1;
else a[n]=2;
}
else{
cout<<"swap "<< i <<"\nthrow "<<i+1<<endl;
cin>>a[i];
if(a[i]==d[i+1]+1)a[i]=1;----------------
else a[i]=2;
}
}
cout<<"! ";
for(int i=1;i<=n;++i)cout<<a[i]<<" ";cout<<endl;
}
int main(){
cin>>tt;
while(tt--)solve();
return 0;
}
F.Permutation Oddness
题面
共 \(t\) 组数据,每组数据:
给定四个整数 \(c_0,c_1,c_2,c_3\) 。
现有一个大小为 \(n=\sum c_i\) 的数组 \(a\) ,定义其奇异度为
\(\displaystyle\sum lowbit(a_i\oplus a_{i+1})\)
你的任务是求出从 \(0\) 到 \(2(n-1)\) 中每一个整数 \(k\) 对应的数组 \(a\) 的个数。
思路
注意到 \(k\) 的范围为 \([0,2(n-1)]\) 于是 \(lowbit(a_i\oplus a_{i+1})\in[0,2]\)
考察 \(lowbit(a_i\oplus a_{i+1})\) 的可能情况:
| (a_i,a_{i+1}) | lowbit |
|---|---|
| (i,i) | 0 |
| (0,1) | 1 |
| (0,3) | 1 |
| (1,2) | 1 |
| (2,3) | 1 |
| (0,2) | 2 |
| (1,3) | 2 |
于是我(题)们(解)发现:
我们将 \(0,2\) 分成一组 \(1,3\) 分成一组后,
组内 \(lowbit\in{0,2}\) ,组间 \(lowbit=1\) ,组数相差至多 \(1\)
定义 \(r_{i,j}\) 表示将 \(c_0\) 个 \(0\) 和 \(c_2\) 个 \(2\) 分成 \(i\) 段,且段内贡献奇异度为 \(j\) 的方案数。
为 \(1,3\) 同理定义 \(b_{i,j}\) 。
我们考虑如何计算 \(r_{i,j}\) 。
设 \(0,2\) 被分成了 \(l\) 个 \(0,2\) 的连续段, \(l_1,l_2\) 分别为其中 \(0,2\) 连续段个数。
那么这样的串的个数是 \(\begin{pmatrix}c_0-1\\l_1-1\end{pmatrix}\cdot\begin{pmatrix}c_2-1\\l_2-1\end{pmatrix}\) 。
假设我们在 \(l-1\) 个不同的 \((a_i,a_{i+1})\) 对中选择 \(k_1\) 个断开, \(c_1+c_2-l\) 个相同的 \((a_i,a_{i+1})\) 对中选择 \(k_2\) 个断开,
则有 \(\begin{pmatrix}l-1\\k_1\end{pmatrix}\cdot\begin{pmatrix}c_0+c_2-l\\k_2\end{pmatrix}\) 种短法。
于是 \(r_{k_1+k_2+1,2(l-1-k_1)}=\begin{pmatrix}c_0-1\\l_1-1\end{pmatrix}\cdot\begin{pmatrix}c_2-1\\l_2-1\end{pmatrix}\cdot\begin{pmatrix}l-1\\k_1\end{pmatrix}\cdot\begin{pmatrix}c_0+c_2-l\\k_2\end{pmatrix}\) 。
那么我们枚举所有可能的 \((l,k_1,k_2)\) 即可在 \(O(n^3)\) 的时间内算出 \(r_{i,j}\) 。
同理,在相同的时间内算出 \(b_{i,j}\) 。
实现
#include<iostream>
#include<vector>
using namespace std;
#define ll long long
const int N=805;
const ll mod=1e9+7;
int tt,c0,c1,c2,c3,n;
ll fac[N],inv[N];
ll qpow(ll a,ll b){
ll ret=1;
while(b){
if(b&1)ret=ret*a%mod;
a=a*a%mod;
b>>=1;
}
return ret;
}
ll C(ll n,ll m){
return inv[n]*inv[m-n]%mod*fac[m]%mod;
}
void calc(int a,int b,vector<vector<ll> >&vec){
int x,y,dif,sam;
ll mul;
for(int i=2;i<=a+b;++i){
if(i&1)x=i/2,y=i-x;
else x=y=i/2;
dif=i-1;
sam=a+b-1-dif;
if(a>=x&&b>=y){
mul=C(x-1,a-1)*C(y-1,b-1)%mod;
for(int j=0;j<=dif;++j)
for(int k=0;k<=sam;++k)
(vec[j+k+1][dif-j]+=mul*C(j,dif)%mod*C(k,sam)%mod)%=mod;
}
if(a>=y&&b>=x){
mul=C(y-1,a-1)*C(x-1,b-1)%mod;
for(int j=0;j<=dif;++j)
for(int k=0;k<=sam;++k)
(vec[j+k+1][dif-j]+=mul*C(j,dif)%mod*C(k,sam)%mod)%=mod;
}
}
}
void solve(){
cin>>c0>>c1>>c2>>c3;
n=c0+c1+c2+c3;
vector<vector<ll> > r(n+1,vector<ll>(n+1,0)),b(n+1,vector<ll>(n+1,0));
calc(c0,c2,r);
calc(c1,c3,b);
vector<ll>ans(2*n-1,0);
for(int i=1;i<=(n+1)/2;++i){
for(int j=0;j<=n;++j)for(int k=0;k<=n;++k){
int oddness=(i+j+k)*2-1;
if(oddness>=0&&oddness<=2*(n-1)){
(ans[oddness]+=r[i][j]*b[i][k]%mod*2%mod)%=mod;
}
}
}
for(int i=1;i<=(n+1)/2&&i+1<=n;++i){
for(int j=0;j<=n;++j)for(int k=0;k<=n;++k){
int oddness=(i+j+k)*2;
if(oddness>=0&&oddness<=2*(n-1)){
(ans[oddness]+=r[i][j]*b[i+1][k]%mod)%=mod;
(ans[oddness]+=r[i+1][j]*b[i][k]%mod)%=mod;
}
}
}
for(int i=0;i<=2*n-2;++i)cout<<ans[i]<<' ';cout<<endl;
}
int main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
fac[0]=inv[0]=1;
for(int i=1;i<=800;++i)fac[i]=fac[i-1]*i%mod;
inv[800]=qpow(fac[800],mod-2);
for(int i=800;i>=2;--i)inv[i-1]=inv[i]*i%mod;
cin>>tt;
while(tt--)solve();
return 0;
}

浙公网安备 33010602011771号