Codeforces Round 704
第一次在赛时 \(\text{AK}\) div2 ,有点感动,不过我相信很快就会 \(\text{fst}\) 光的。
Problem A
你就取个模就好了?
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
void solve(){
int a,b,c,p;
cin>>p>>a>>b>>c;
int res=min((a-p%a)%a,min((b-p%b)%b,(c-p%c)%c));
printf("%lld\n",res);
}
signed main(){
int T;cin>>T;
while(T--) solve();
}
Problem B
你发现只要贪心就好了,让最大的尽量靠上,满足前一个条件之后再使得剩下的中最大的也尽量靠上,然后就好了。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,a[N],b[N];
void solve(){
cin>>n;
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
for(int i=1;i<=n;++i){
if(a[b[i-1]]>a[i]) b[i]=b[i-1];
else b[i]=i;
}
int tmp=n;
while(tmp){
for(int i=b[tmp];i<=tmp;++i) printf("%d ",a[i]);
tmp=b[tmp]-1;
}
printf("\n");
return ;
}
int main(){
int T;cin>>T;
while(T--) solve();
}
Problem C
这道题你可以处理出第二个串的每一个位置在满足前面(或后面)每一个位置在第一个串中都匹配上的时候,位于第一个串中尽量靠前(或后)的位置是哪里。
这样的话你就可以枚举第二个串的每一个间隔,让前半部分尽可能靠前,后半部分尽可能靠后,然后去一个 \(\max\) 就可以了。可以证明这样不会漏掉答案。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,m;
char s[N],t[N];
int nxt[N][27];
int L[N],R[N];
int main(){
cin>>n>>m,scanf("%s%s",s+1,t+1);
for(int i=1;i<=26;++i) nxt[n+1][i]=n+1;
for(int i=n;i>=1;--i){
for(int j=1;j<=26;++j){
if(j==s[i]-'a'+1) nxt[i][j]=i;
else nxt[i][j]=nxt[i+1][j];
}
}
int tmp=0;
for(int i=1;i<=m;++i){
L[i]=nxt[tmp+1][t[i]-'a'+1];
tmp=nxt[tmp+1][t[i]-'a'+1];
}
for(int i=1;i<=26;++i) nxt[0][i]=0;
for(int i=1;i<=n;++i){
for(int j=1;j<=26;++j){
if(j==s[i]-'a'+1) nxt[i][j]=i;
else nxt[i][j]=nxt[i-1][j];
}
}
tmp=n+1;
for(int i=m;i>=1;--i){
R[i]=nxt[tmp-1][t[i]-'a'+1];
tmp=nxt[tmp-1][t[i]-'a'+1];
}
int res=0;
for(int i=1;i<m;++i) res=max(res,R[i+1]-L[i]);
printf("%d\n",res);
return 0;
}
Problem D
首先因为最高位强制为 \(1\) ,就将 \(b\) 先减去 \(1\) 。
可以证明,在 \(a>0,b>0\) 的条件下,最大的可能值一定是 \(a+b-2\) 。
方案的话就是用 \(1\) 个 \(0\) 和 \(b-1\) 个 \(1\) 可以构造出 \(b-1\) 个 \(1\) ,用 \(1\) 个 \(1\) 和 \(a-1\) 个 \(0\) 可以构造出 \(a-1\) 个 \(1\) ,交错排列即可。
然后如果 \(a\) 和 \(b\) 中存在 \(0\) ,最大就只能是 \(0\) 。
应该就是这样。
发现 \(D\) 果然炸了。
发现我上面的猜测完全错了,实际上非常简单,你只需要保证有一个首尾的 \(0\) 和 \(1\) 互换,然后剩余的部分完全相同,就可以产生互换的区间长度 \(-1\) 的贡献,然后最大值就是 \(a+b-1\) (此处 \(b\) 已减一),特判一下 \(k=0\) 就可以了。
#include<bits/stdc++.h>
using namespace std;
const int N=4e5+5;
int a,b,k;
int x[N],y[N];
int main(){
cin>>a>>b>>k;
if(k==0){
printf("Yes\n");
for(int i=1;i<=b;++i) printf("1");
for(int i=1;i<=a;++i) printf("0");
printf("\n");
for(int i=1;i<=b;++i) printf("1");
for(int i=1;i<=a;++i) printf("0");
printf("\n");
return 0;
}
x[a+b]=y[a+b]=1,b--;
if(!a||!b||a+b-1<k) return printf("No\n"),0;
printf("Yes\n");
for(int i=a+b;i>=a+1;--i) x[i]=y[i]=1;
for(int i=a;i>=1;--i) x[i]=y[i]=0;
for(int i=a+b;i>k;--i) if(y[i]&&!y[i-k]){swap(y[i],y[i-k]);break;}
for(int i=a+b+1;i>=1;--i) printf("%d",x[i]);
printf("\n");
for(int i=a+b+1;i>=1;--i) printf("%d",y[i]);
printf("\n");
return 0;
}
Prblem E
好题好题。
比较显然的,如果任意两个之间存在不同个数多于 \(4\) ,那么一定不可行。
我们可以将第一个和后面的每一个进行比对,找出差距最大的一个,如果差距最大的小于 \(2\) ,那么直接输出第一个即可,如果差距大于 \(4\) ,那么一定不可行。
那么现在相当于我们只有最多 \(4\) 个位置是不确定的,你直接暴力判断即可。
发现也炸了,我是傻逼。
在差距为 \(3\) 的时候不一定是位于 \(1\) 和差距最大的那个之中,所以说两种暴搜是不一样的。。。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+5;
int n,m,tmp=1,cnt[N],a[N];
map<int,map<int,int> > mp;
bool tag[N];
void dfs1(int now){
if(now>m){
for(int i=1;i<=n;++i){
int cnt=0;
for(int j=1;j<=m;++j)
cnt+=(mp[i][j]!=a[j]);
if(cnt>2) return ;
}
printf("Yes\n");
for(int j=1;j<=m;++j) printf("%d ",a[j]);
printf("\n");
exit(0);
}
if(tag[now]) a[now]=mp[1][now],dfs1(now+1);
else{
a[now]=mp[1][now],dfs1(now+1);
a[now]=mp[tmp][now],dfs1(now+1);
}
}
void dfs2(int now,int cnt1,int cnt2,int cnt3){
if(now>m){
if(!cnt1||!cnt2) return ;
for(int i=1;i<=n;++i){
int cnt=0;
for(int j=1;j<=m;++j){
if(a[cnt3]<0&&j==cnt3) continue;
cnt+=(mp[i][j]!=a[j]);
}
if(a[cnt3]<0&&cnt==2) a[cnt3]=mp[i][cnt3];
if(cnt>2) return ;
}
printf("Yes\n");
for(int j=1;j<=m;++j){
if(a[j]==-1) printf("1 ");
else printf("%d ",a[j]);
}
printf("\n");
exit(0);
}
if(tag[now]) a[now]=mp[1][now],dfs2(now+1,cnt1,cnt2,cnt3);
else{
if(!cnt1) a[now]=mp[1][now],dfs2(now+1,cnt1+1,cnt2,cnt3);
if(!cnt2) a[now]=mp[tmp][now],dfs2(now+1,cnt1,cnt2+1,cnt3);
a[now]=-1,dfs2(now+1,cnt1,cnt2,now);
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j)
scanf("%d",&mp[i][j]);
}
for(int i=2;i<=n;++i){
for(int j=1;j<=m;++j)
cnt[i]+=(mp[1][j]!=mp[i][j]);
if(cnt[i]>4) return printf("No\n"),0;
if(cnt[i]>cnt[tmp]) tmp=i;
}
// printf("%d %d\n",tmp,cnt[tmp]);
if(cnt[tmp]<=2){
printf("Yes\n");
for(int j=1;j<=m;++j) printf("%d ",mp[1][j]);
return printf("\n"),0;
}
for(int j=1;j<=m;++j) tag[j]=(mp[1][j]==mp[tmp][j]);
if(cnt[tmp]==4) dfs1(1),printf("No\n");
else dfs2(1,0,0,0),printf("No\n");
return 0;
}
/*
5 5
1 2 3 4 5
6 7 3 4 8
1 9 3 10 11
1 12 3 4 15
1 9 14 4 16
1 9 3 4 8
*/