CF1553D. Backspace
考点:尺取法+贪心
。
贪心策略是尽量选最多。因为 L1
和 L2
奇偶性相同,所以选前面一段一定更优。
然后是开头段的情况,这个可以直接算, (n-m)&1
。
#include<bits/stdc++.h>
#define fi first
#define se second
#define ll long long
#define PII pair<int,int>
#define All(x) x.begin(),x.end()
using namespace std;
const int mx=1e5;
char a[mx+5],b[mx+5];
int n,m;
int main() {
int T; scanf("%d",&T);
while(T--) {
scanf("%s%s",a+1,b+1),n=strlen(a+1),m=strlen(b+1);
a[++n]='1',b[++m]='1';
int p=1,lastpos=0;
int p2=1,lastpos2=-1;
for(int i=1;i<=n;i++) {
if(a[i]==b[p]&&(i-lastpos-1)%2==0) {
for(;p<=m&&a[i]==b[p];i++,p++);
lastpos=i-1;
}
}
for(int i=1;i<=n;i++) {
if(a[i]==b[p2]&&((i-lastpos2-1)%2==0)) {
for(;p2<=m&&a[i]==b[p2];i++,p2++);
lastpos2=i-1;
}
}
printf("%s\n",(p==m+1||p2==m+1)?"yes":"no");
}
}
CF1553E Permutation Shift
考点:置换+暴力
。
先来看两个任意排列的最少交换次数,连边 rnk1[i]->rnk2[i]
答案就是 n-cnt
,cnt
表示环的数量。
到本题来,其实就是将 p[i]->i
连边,移动后就是 p[i]->i+k
。
考虑 m的限制
。m<=n/3 <=> n-cnt<=n/3 <=> cnt>=2n/3
,所以长度为 1
的环 >=n/3
,故满足条件的 k<=3
。最后把满足 >=n/3
的 k
暴力判断即可。
#include<bits/stdc++.h>
#define fi first
#define se second
#define ll long long
#define PII pair<int,int>
#define All(x) x.begin(),x.end()
using namespace std;
const int mx=3e5+5;
int n,m,p[mx],vis[mx],tong[mx];
vector<int> ans;
bool check(int k) {
int cnt=0;
for(int i=0;i<n;i++) vis[i]=0;
for(int i=0;i<n;i++) {
if(vis[i]) continue;
for(int j=i;!vis[j];j=(p[j]+k)%n) vis[j]=1;
cnt++;
}
return n-cnt<=m;
}
int main() {
int T; scanf("%d",&T);
while(T--) {
scanf("%d%d",&n,&m),ans.clear();
for(int i=0;i<n;i++) tong[i]=0;
for(int i=0,x;i<n;i++) scanf("%d",&x),x--,p[i]=x,tong[(i+n-x)%n]++;
// for(int i=0;i<n;i++) printf("p[%d]=%d\n",i,p[i]);
for(int i=0;i<n;i++) {
// printf("tong[%d]=%d\n",i,tong[i]);
if(tong[i]>=n/3&&check(i)) {
ans.push_back(i);
}
}
printf("%d",ans.size());
for(auto x:ans) {
printf(" %d",x);
}
printf("\n");
}
}
CF1553F Pairwise Modulo
考点 :分块/树状数组
树状数组比较难想。分块码量较大。
a[i] mod a[j] = a[i] - (a[i]/a[j]) * a[j]
注意到 a[i]
两两不同。