Educational Codeforces Round 70 (Rated for Div. 2) A,B,C,D,E

S t r i n g F o r c e s StringForces StringForces 为什么他们代码能力那么强!!!


A. You Are Given Two Binary Strings…

传送门


Solution

显然只需要把最低位的 1 1 1消掉就好了

#include<cstdio>
#include<algorithm>
#include<cstring>
const int MAXN = 1e5+10;
int n,m;
char b1[MAXN],b2[MAXN];
void solve(){
	scanf("%s%s",b1+1,b2+1);
	n=strlen(b1+1);
	m=strlen(b2+1);
	std::reverse(b1+1,b1+1+n);
	std::reverse(b2+1,b2+1+m);
	int pos=1;
	while(b2[pos]!='1')
		pos++;
	int i;
	for(i=pos;i;i++){
		if(b1[i]=='1')
			break;
	}
	printf("%d\n",i-pos);
}
int main(){
	int T;
	scanf("%d",&T);
	while(T--)
		solve();
	return 0;
}

B. You Are Given a Decimal String…

传送门


Solution

假设从 a i a_i ai转移到 a j a_j aj,可以看作从 0 0 0转移到 ( a i − a j + 10 ) % 10 (a_i-a_j+10)\%10 (aiaj+10)%10
所以可以枚举每次选的两个数 x , y x,y x,y
f [ n ] f[n] f[n]为用这两个数凑出 n n n最少要多少步
f [ x ] = f [ y ] = 1 f[x]=f[y]=1 f[x]=f[y]=1
转移 f [ ( n + x ) % 10 ] = f [ n ] + 1 f[(n+x)\%10]=f[n]+1 f[(n+x)%10]=f[n]+1
f [ ( n + y ) % 10 ] = f [ n ] + 1 f[(n+y)\%10]=f[n]+1 f[(n+y)%10]=f[n]+1
然后像 s p f a spfa spfa那样转移就好了
如果不好理解,可以直接理解成最短路
具体细节看代码

#include<cstdio>
#include<queue>
#include<cstring>
const int MAXN = 3e6;
char str[MAXN];
int n,data[10],f[22];
bool inq[22];
void solve(int a,int b){
	data[1]=a;data[2]=b;
	for(int i=1;i<10;i++)
		f[i]=0x3f3f3f3f;
	f[0]=0x3f3f3f3f;
	for(int i=0;i<10;i++)
		inq[i]=0;
	std::queue<int> Q;
	Q.push(a);Q.push(b);
	f[a]=f[b]=1;
	inq[a]=1;inq[b]=1;
	while(Q.size()){
		int cur=Q.front();
		Q.pop();
		inq[cur]=0;
		for(int i=1;i<=2;i++){
			int t=(cur+data[i])%10;
			if(f[t]>f[cur]+1){
				f[t]=f[cur]+1;
				if(!inq[t]){
					inq[t]=1;
					Q.push(t);
				}
			}
		}
	}
}
typedef long long ll;
ll ans[22][22];
int main(){
	scanf("%s",str+1);
	n=strlen(str+1);
	for(int i=1;i<=n;i++)
		str[i]-='0';
	for(int i=0;i<10;i++){
		for(int j=0;j<10;j++){
			ll tmp=0;
			solve(i,j);
			int t=0;
			for(int k=2;k<=n;k++){
				t=(str[k]-t+10)%10;
				if(f[t]==0x3f3f3f3f){
					tmp=-1;
					break;
				}
				tmp += f[t]-1;
				t=str[k];
			}
			ans[i][j]=tmp;
		}
	}
	for(int i=0;i<10;i++){
		for(int j=0;j<10;j++){
			printf("%lld ",ans[i][j]);
		}
		puts("");
	}
	return 0;
}

C. You Are Given a WASD-string…

传送门


Solution

模拟题……
如果不考虑新添加的那个字符的话。
答案只跟运动中的 x x x y y y的极大极小值有关。
为了方便描述,现在把这 4 4 4个量合称运动空间。
如果可以处理出前缀和后缀运动空间,那么就可以枚举在哪个位置放哪个字符,计算答案。
其实前缀是不需要保存的,因为可以在枚举过程中得到。
主要考虑后缀怎么处理,和如何把前缀和后缀合起来。
其实这都属于“如何把前缀和后缀合起来”这个问题。(处理后缀相当于这一步的运动空间和之后的运动空间的合成
假设我们已知前缀和后缀的运动空间和现在点位置在 ( x , y ) (x,y) (x,y)
那么只需要把后缀运动空间的4个量分别 + x +x +x + y +y +y,然后和前缀大的取大,小的取小,这实际上就是坐标系的变换。
然后就做完了……

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
typedef long long ll;
const int MAXN = 3e5;
char str[MAXN];
int n;
struct E{
	int mxx,mnx,mxy,mny;
	void init(){
		mxx=0;
		mnx=0;
		mxy=0;
		mny=0;
	}
	void update(int x,int y){
		mxx=max(mxx,x); mnx=min(mnx,x);
		mxy=max(mxy,y); mny=min(mny,y);		
	}
	E operator ^ (E b){
		E ret;
		ret.mxx = max(mxx,b.mxx);
		ret.mnx = min(mnx,b.mnx);
		ret.mxy = max(mxy,b.mxy);
		ret.mny = min(mny,b.mny);
		return ret;
	}
	ll getans(){
		ll ans =0;
		ans = ((ll)(mxx-mnx+1)) * ((ll)(mxy-mny+1));
		return ans;
	}
	E add(int x,int y){
		E ret = *this;
		ret.mxx+=x;	ret.mnx+=x;
		ret.mxy+=y; ret.mny+=y;
		return ret;
	}
	E trans(int x,int y){
		E ret = (*this);
		ret.update(x,y);
		return ret;
	}
};
E pre[MAXN],suf[MAXN];
void solve(){
	scanf("%s",str+1);
	n=strlen(str+1);
	int x=0,y=0;
	for(int i=0;i<=n+1;i++){
		pre[i].init();
		suf[i].init();
	}
	for(int i=1;i<=n;i++){
		if(str[i]=='W'){x++;}else if(str[i]=='S'){x--;}else if(str[i]=='A'){y--;}else{y++;}
		pre[i] = pre[i-1];
		pre[i].update(x,y);
	}
	
	for(int i=n;i>=1;i--){
		x=y=0;
		if(str[i]=='W'){x++;}else if(str[i]=='S'){x--;}else if(str[i]=='A'){y--;}else{y++;}
		suf[i].update(x,y);
		E tmp = suf[i+1].add(x,y);
		suf[i] = suf[i] ^ tmp;		
	}
	ll ans = 0x7fffffffffffffff;
	x=y=0;
	ans = min(ans,suf[1].getans());
	for(int i=1;i<n;i++){
		if(str[i]=='W'){x++;}else if(str[i]=='S'){x--;}else if(str[i]=='A'){y--;}else{y++;}
		E tmp=suf[i+1]; E cur;
		cur = pre[i].trans(x+1,y) ^ tmp.add(x+1,y);	ans = min(ans,cur.getans());
		cur = pre[i].trans(x-1,y) ^ tmp.add(x-1,y);	ans = min(ans,cur.getans());
		cur = pre[i].trans(x,y-1) ^ tmp.add(x,y-1);	ans = min(ans,cur.getans());
		cur = pre[i].trans(x,y+1) ^ tmp.add(x,y+1);	ans = min(ans,cur.getans());
	}
 
	printf("%lld\n",ans);
}
int main(){
	int T;
	scanf("%d",&T);
	while(T--)
		solve();
	return 0;
}

D. Print a 1337-string…

传送门


Solution

先考虑 133333...33337 133333...33337 133333...33337这样情况假设其中有 m m m 3 3 3那么对答案的贡献就是 C m 2 C_{m}^{2} Cm2
贪心地让 m m m取到尽可能大的值。
剩下的考虑如果再在第二个 3 3 3后面加 n n n 7 7 7那么对答案的贡献就是 n n n
于是剩下的就在第二个 3 3 3后面填上相应多个 7 7 7就好了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
void solve(){	ll n;
	scanf("%lld",&n);
	printf("133");
 
	ll i;
	for(i=2;i;i++){
		if((i*(i+1)/2) > n){
			break;	
		}
	}
	n -= (i-1)*i/2;
	for(int j=1;j<=n;j++)putchar('7');
	for(int j=3;j<=i;j++)putchar('3');
	puts("7");
	ll tmp = 0;
	tmp += 3  + n + i - 1;
}
int main(){
	int T;
	scanf("%d",&T);
	while(T--)
		solve();
	return 0;
}

E. You Are Given Some Strings…

传送门


Solution

做这个题的时候被误导了一下,于是弱智的我写的后缀数组……
看看有时间再补个其他正常做法吧……

SA 做法

如果只考虑一个字符串匹配的话,可以想到把所有的字符串用特殊的字符连接然后建 S A SA SA
枚举每一个要匹配的字符串,在 S A SA SA数组上左右二分(这里需要 h e i g h t height height数组, s t 表 st表 st),在二分出的区间上打上 + 1 +1 +1的标记(需要差分)。
打完标记之后扫一遍就可以处理出以主串每个位置开头就多少个匹配。
然后这个题要两个字符串拼起来,那就把每个字符串包括主串分别反过来按上面的套路连起来。
就可以处理出以主串每个位置结尾有多少匹配。
相邻的开头结尾乘一乘就好了

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dep(i,a,b) for(int i=a;i>=b;i--)
typedef long long ll;
const int MAXN = 7e5;
const int MAXM = 2e5+10;
struct ele{
	int id,x,y;	
};
int Bin[MAXN];
void sorty(ele *s,ele *bs,int len){
	rep(i,0,6e5+10)Bin[i]=0;
	rep(i,1,len)Bin[s[i].y]++;
	rep(i,1,6e5+10)Bin[i]+=Bin[i-1];
	dep(i,len,1)bs[Bin[s[i].y]--]=s[i];
	rep(i,1,len)s[i]=bs[i];
}
void sortx(ele *s,ele *bs,int len){
	rep(i,0,6e5+10)Bin[i]=0;
	rep(i,1,len)Bin[s[i].x]++;
	rep(i,1,6e5+10)Bin[i]+=Bin[i-1];
	dep(i,len,1)bs[Bin[s[i].x]--]=s[i];
	rep(i,1,len)s[i]=bs[i];
}
int count(ele *s,int len){
	ele tmp=s[1];
	int ret=0;
	s[1].x=++ret;
	rep(i,2,len){
		if(tmp.x==s[i].x&&tmp.y==s[i].y){
			tmp=s[i];
			s[i].x=ret;
		}else{
			tmp=s[i];
			s[i].x=++ret;
		}
	}
	return ret;
}
void sortid(ele *s,ele *bs,int len){
	rep(i,0,6e5+10)Bin[i]=0;
	rep(i,1,len)Bin[s[i].id]++;
	rep(i,1,6e5+10)Bin[i]+=Bin[i-1];
	dep(i,len,1)bs[Bin[s[i].id]--]=s[i];
	rep(i,1,len)s[i]=bs[i];
}
void build(int *s,int len,int *h,int *rk,int *sa){
	static ele SA[MAXN],BUF[MAXN];
	int k=1;
	rep(i,1,len){SA[i].id=i;SA[i].x=s[i];SA[i].y=0;}
	while(k<len){
		rep(i,1,len){
			if(i+k<=len){SA[i].y=SA[i+k].x;}
			else{SA[i].y=0;}
		}
		sorty(SA,BUF,len);
		sortx(SA,BUF,len);
		int tmp=count(SA,len);
		sortid(SA,BUF,len);
		if(tmp == len)
			break;
		k<<=1;
	}	
	rep(i,1,len){rk[i]=SA[i].x;sa[SA[i].x]=i;}
	k=0;
	rep(i,1,len){
		if(rk[i]==1)continue; 
		int j=sa[rk[i]-1];
		while(i+k<=len&&j+k<=len&&s[i+k]==s[j+k])k++;
		h[rk[i]]=k;
		if(k>0)k--;
	}
}
 
int n,tot,pos[MAXM],alpha,len,str1[MAXN],str2[MAXN],length[MAXN];
char buf[MAXM];
int f[MAXN],sa[MAXN],rk[MAXN],g[MAXN],g2[MAXN],h[MAXN],rmq[21][MAXN];
int getrmq(int l,int r){
	int t=(int)(log(r-l+1)/log(2));
	return min(rmq[t][l],rmq[t][r-(1<<t)+1]);
}
int main(){
	alpha='z'+2;
	scanf("%s",buf+1);
	len=strlen(buf+1);
	rep(i,1,len)str1[i]=str2[len-i+1]=(int)buf[i];
	tot=len+1;
	str1[tot]=str2[tot]=++alpha;
	scanf("%d",&n);
	rep(i,1,n){
		pos[i]=tot+1;
		scanf("%s",buf+1);
		int curLen=strlen(buf+1);
		length[i]=curLen;
		rep(j,1,curLen){
			str1[++tot]=(int)buf[j];
			str2[tot]=(int)buf[curLen-j+1];
		}
		str1[++tot]=++alpha;
		str2[tot]=alpha;
	}
	build(str1,tot,h,rk,sa);
	rep(i,1,tot)rmq[0][i]=h[i];
	rep(i,1,20)
		rep(j,1,tot){
			if(j+(1<<i)-1>tot)break;
			rmq[i][j]=min(rmq[i-1][j],rmq[i-1][j+(1<<(i-1))]);
		}
	rep(i,1,n){
		int p=pos[i];
		p=rk[p];
		int l=1,r=p-1,cur_ans=-1;
		while(l<=r){
			int mid=(l+r)>>1;
			if(getrmq(mid+1,p)>=length[i]){
				cur_ans=mid;
				r=mid-1;
			}else{
				l=mid+1;
			}
		}
		if(cur_ans==-1)
			cur_ans=p;
		f[cur_ans]++;
		l=p+1;r=tot;cur_ans=-1;
		while(l<=r){
			int mid=(l+r)>>1;
			if(getrmq(p+1,mid)>=length[i]){
				cur_ans=mid;
				l=mid+1;
			}else{
				r=mid-1;
			}
		}
		if(cur_ans==-1)
			cur_ans=p;
		f[cur_ans+1]--;
	}
	
	int tmp=0;
	rep(i,1,tot){
		tmp += f[i];
		f[i]=0;
		if(sa[i]<=len){
			g[sa[i]]=tmp;
		}
	}
	build(str2,tot,h,rk,sa);
	rep(i,1,tot)rmq[0][i]=h[i];
	rep(i,1,20)rep(j,1,tot){
		if(j+(1<<i)-1>tot)break;
		rmq[i][j]=min(rmq[i-1][j],rmq[i-1][j+(1<<(i-1))]);
	}
	rep(i,1,n){
		int p=pos[i];
		p=rk[p];
		int l=1,r=p-1,cur_ans=-1;
		while(l<=r){
			int mid=(l+r)>>1;
			if(getrmq(mid+1,p)>=length[i]){
				cur_ans=mid;
				r=mid-1;
			}else{
				l=mid+1;
			}
		}
		if(cur_ans==-1)
			cur_ans=p;
		f[cur_ans]++;
		l=p+1;r=tot;cur_ans=-1;
		while(l<=r){
			int mid=(l+r)>>1;
			if(getrmq(p+1,mid)>=length[i]){
				cur_ans=mid;
				l=mid+1;
			}else{
				r=mid-1;
			}
		}
		if(cur_ans==-1)
			cur_ans=p;
		f[cur_ans+1]--;
	}
	tmp=0;
	rep(i,1,tot){
		tmp += f[i];
		f[i]=0;
		if(sa[i]<=len){
			g2[len-sa[i]+1]=tmp;
		}
	}
	ll ans=0;
	rep(i,1,len-1){
		ans+=(ll)g2[i]*g[i+1];
	}	
	printf("%lld",ans);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值