Codeforces Round #704 (Div. 2)
Codeforces 难得有一次不熬夜的比赛。
A
送分题,记得开 long long。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define int long long
signed main()
{
int T;
scanf("%lld",&T);
while(T--)
{
int p,a,b,c;
scanf("%lld %lld %lld %lld",&p,&a,&b,&c);
int ta=(p+a-1)/a*a,tb=(p+b-1)/b*b,tc=(p+c-1)/c*c;
printf("%lld\n",min(min(ta-p,tb-p),tc-p));
}
return 0;
}
B
\(\sum\limits_{i = 1}^{n}{n^{n - i} \cdot p_i}\) 可以看作是一个 \(n\) 进制数,所以 \(p_1\) 越大越好,其次是 \(p_2\),以此类推。从 \(n\) 到 \(1\) 枚举,如果当前的数能够安排到前面就安排到前面,按照题意模拟即可。时间复杂度 \(\mathcal O(n)\)(如果实现的好)。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int N=1e5;
int a[N+10],p[N+10];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
p[a[i]]=i;
}
int pos=n+1;
vector<int> ans;
for(int i=n;i;i--)
{
for(int j=p[i];j<pos;j++)
ans.push_back(a[j]);
if(p[i]<pos) pos=p[i];
}
for(int i=0;(unsigned)i<ans.size();i++) printf("%d ",ans[i]);
putchar('\n');
}
return 0;
}
C
分别对 \(s\) 从前往后和从后往前扫一遍求出 \(pre_i\) 和 \(suf_i\),\(pre_i\) 表示在 \(s\) 中能够满足 \(\forall k\in[1,i],s_{j_k}=t_k\) 的子序列 \(s_{j_1}s_{j_2}\cdots s_{j_i}\)(\(1\le j_1<j_2<\cdots< j_i\le n\)) 中最小的 \(j_i\),\(suf_i\) 表示最大的 \(j_i\),答案就是 \(\max\limits_{i=1}^{m-1} \{suf_{i+1}-pre_i\}\)。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=2e5;
char s[N+10],t[N+10];
int pre[N+10],suf[N+10];
int main()
{
int n,m;
scanf("%d%d%s%s",&n,&m,s+1,t+1);
for(int i=1,j=1;i<=n&&j<=m;i++)
{
if(s[i]==t[j])
{
pre[j]=i;
j++;
}
}
// for(int i=1;i<=m;i++) printf("%d ",pre[i]);/
for(int i=n,j=m;i&&j;i--)
{
if(s[i]==t[j])
{
suf[j]=i;
j--;
}
}
int ans=0;
for(int i=1;i<n;i++)
ans=max(ans,suf[i+1]-pre[i]);
printf("%d",ans);
return 0;
}
D
希望出题人没事。
将 \(x\) 的二进制表示成 \(x_1x_2\cdots x_{a+b}\),\(y\) 表示成 \(y_1y_2\cdots y_{a+b}\)。令 \(x_1=y_1=1\),\(x_{a+b-k}=y_{a+b}=1\),然后把所有剩余的 \(1\) 安排在满足 \(a_i=b_i=0\) 的位置上即可。如果有任意一个步骤无法满足,则输出 No
并 return 0
。
要特判 \(\bold{k=0}\) 和 \(\bold{a=0}\) 的情况。
#include<bits/stdc++.h>
using namespace std;
const int N=2e5;
int x[N+10],y[N+10];
int main()
{
int a,b,k;
scanf("%d %d %d",&a,&b,&k);
swap(a,b);
int n=a+b;
int ta=a,tb=b;
if(k==0)
{
puts("Yes");
// ta--;
for(int i=1;i<=ta;i++) putchar('1');
for(int i=1;i<=tb;i++) putchar('0');
putchar('\n');
for(int i=1;i<=ta;i++) putchar('1');
for(int i=1;i<=tb;i++) putchar('0');
return 0;
}
if(b==0)
{
if(k!=0)
{
puts("No");
return 0;
}
else
{
puts("Yes");
for(int i=1;i<=a;i++) putchar('1');
putchar('\n');
for(int i=1;i<=a;i++) putchar('1');
putchar('\n');
}
}
x[1]=y[1]=1;
ta--;
if(ta<0)
{
puts("No");
return 0;
}
if(n-k<=1)
{
puts("No");
return 0;
}
x[n-k]=y[n]=1;
ta--;
if(ta<0)
{
puts("No");
return 0;
}
for(int i=1;i<=n&&ta;i++)
{
if(!x[i]&&!y[i])
{
x[i]=y[i]=1;
ta--;
}
}
// if(ta>0)
// {
// puts("No");
// return 0;
// }
printf("Yes\n");
for(int i=1;i<=n;i++) printf("%d",x[i]);
putchar('\n');
for(int i=1;i<=n;i++) printf("%d",y[i]);
}
E
定义两行之间的差异值 \(\mathrm{diff}(x,y)=\sum\limits_{i=1}^m[s_{x,i}\not=s_{y,i}]\)。令 \(w=\max\limits_{i=2}^n\{\mathrm{diff(1,i)}\}\),\(id\) 表示取到 \(w\) 的行的编号,接下来就是 喜 闻 乐 见 的分类讨论:
- 若 \(w\le 2\),直接输出第一行即可;
- 若 \(w\ge 5\),无解;
- 若 \(w=4\),则第一行与第 \(id\) 行一定都与答案的 \(\mathrm{diff}\) 都是 \(2\),枚举第 \(id\) 行哪两个数是正确的,将它们 copy 到第一行中,不断验证当前答案是否正确,如果不正确就还原初始状态,继续枚举;
- 若 \(w=3\),则第一行与第 \(id\) 行分别有一个答案是正确的,有一个答案都无法确定是否是正确的。枚举都正确的那两个数,将第 \(id\) 行正确的数 copy 到第一行中,然后假设第一行无法确定的数是正确的,验证一遍,如果存在一行 \(x\) 使得 \(\mathrm{diff}\ge 3\) 就把第 \(x\) 行于第一行无法确定的数同列的数 copy 到第一行中并再验证一遍,如果还是不行就还原初始状态,继续枚举。
情况三最多验证 \(\mathrm{C}_4^2=6\) 遍,情况四最多验证 \(2\mathrm{C}_3^2=6\) 遍,是两个可以接受的常数。总的时间复杂度是 \(\mathcal O(nm)\)。
#include<bits/stdc++.h>
using namespace std;
const int N=250000;
vector<int> a[N+10];
int n,m;
int dif(vector<int> x,vector<int> y)
{
int ans=0;
for(int i=1;i<=m;i++)
ans+=(x[i]!=y[i]);
return ans;
}
bool check()
{
for(int i=2;i<=n;i++)
if(dif(a[1],a[i])>2)
return false;
return true;
}
int check1()
{
for(int i=2;i<=n;i++)
if(dif(a[1],a[i])>2)
return i;
return 0;
}
int pos[N+10],cnt=0;
int main()
{
// int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
a[i].push_back(0);
for(int j=1;j<=m;j++)
{
int x;
scanf("%d",&x);
a[i].push_back(x);
}
}
int mx=0,id=-1;
for(int i=2;i<=n;i++)
{
int tmp=dif(a[1],a[i]);
if(tmp>mx)
{
mx=tmp;
id=i;
}
}
if(mx<=2)
{
puts("Yes");
for(int i=1;i<=m;i++) printf("%d ",a[1][i]);
}
else if(mx>=5)
puts("No");
else if(mx==4)
{
for(int i=1;i<=m;i++)
if(a[1][i]!=a[id][i])
pos[++cnt]=i;
for(int i=1;i<=cnt;i++)
{
for(int j=i+1;j<=cnt;j++)
{
int pi=pos[i],pj=pos[j];
int ti=a[1][pi],tj=a[1][pj];
a[1][pi]=a[id][pi];
a[1][pj]=a[id][pj];
if(check())
{
puts("Yes");
for(int i=1;i<=m;i++) printf("%d ",a[1][i]);
return 0;
}
a[1][pi]=ti;
a[1][pj]=tj;
}
}
puts("No");
}
else if(mx==3)
{
for(int i=1;i<=m;i++)
if(a[1][i]!=a[id][i])
pos[++cnt]=i;
// printf("pos:\n");
// for(int i=1;i<=cnt;i++) printf("%d ",pos[i]);
for(int i=1;i<=cnt;i++)
{
for(int j=1;j<=cnt;j++)
{
if(i==j) continue;
int pi=pos[i],pj=pos[j],pk=pos[6-i-j];
int ti=a[1][pi],tj=a[1][pj],tk=a[1][pk];
// a[1][pi]=a[id][pi];
a[1][pj]=a[id][pj];
int tmp=check1();
if(!tmp)
{
puts("Yes");
for(int i=1;i<=m;i++) printf("%d ",a[1][i]);
return 0;
}
a[1][pk]=a[tmp][pk];
tmp=check1();
if(!tmp)
{
puts("Yes");
for(int i=1;i<=m;i++) printf("%d ",a[1][i]);
return 0;
}
a[1][pi]=ti;
a[1][pj]=tj;
a[1][pk]=tk;
}
}
puts("No");
}
return 0;
}