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
",min(min(ta-p,tb-p),tc-p));
}
return 0;
}
B
(sumlimits_{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('
');
}
return 0;
}
C
分别对 (s) 从前往后和从后往前扫一遍求出 (pre_i) 和 (suf_i),(pre_i) 表示在 (s) 中能够满足 (forall kin[1,i],s_{j_k}=t_k) 的子序列 (s_{j_1}s_{j_2}cdots s_{j_i})((1le j_1<j_2<cdots< j_ile n)) 中最小的 (j_i),(suf_i) 表示最大的 (j_i),答案就是 (maxlimits_{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_2cdots x_{a+b}),(y) 表示成 (y_1y_2cdots 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
。
要特判 (old{k=0}) 和 (old{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('
');
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('
');
for(int i=1;i<=a;i++) putchar('1');
putchar('
');
}
}
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
");
for(int i=1;i<=n;i++) printf("%d",x[i]);
putchar('
');
for(int i=1;i<=n;i++) printf("%d",y[i]);
}
E
定义两行之间的差异值 (mathrm{diff}(x,y)=sumlimits_{i=1}^m[s_{x,i} ot=s_{y,i}])。令 (w=maxlimits_{i=2}^n{mathrm{diff(1,i)}}),(id) 表示取到 (w) 的行的编号,接下来就是 喜 闻 乐 见 的分类讨论:
- 若 (wle 2),直接输出第一行即可;
- 若 (wge 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) 遍,情况四最多验证 (2mathrm{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:
");
// 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;
}