Educational Codeforces Round 85 (Rated for Div. 2) 题解

来记录一下翻车惨案/kk

A

判判判就好了(题面是真的难读)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double db;
typedef vector<int> vi;
typedef pair<int,int> pii;
const int N=100000;
const db pi=acos(-1.0);
#define lowbit(x) (x)&(-x)
#define sqr(x) (x)*(x)
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define go(u,i) for (register int i=head[u],v=sq[i].to;i;i=sq[i].nxt,v=sq[i].to)
#define fir first
#define sec second
#define mkp make_pair
#define pb push_back
#define maxd 998244353
#define eps 1e-8
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
    while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
    return x*f;
}

namespace My_Math{
	#define N 100000

	int fac[N+100],invfac[N+100];

	int add(int x,int y) {return x+y>=maxd?x+y-maxd:x+y;}
	int dec(int x,int y) {return x<y?x-y+maxd:x-y;}
	int mul(int x,int y) {return 1ll*x*y%maxd;}
	ll qpow(ll x,int y)
	{
		ll ans=1;
		while (y)
		{
			if (y&1) ans=mul(ans,x);
			x=mul(x,x);y>>=1;
		}
		return ans;
	}
	int getinv(int x) {return qpow(x,maxd-2);}

	int C(int n,int m)
	{
		if ((n<m) || (n<0) || (m<0)) return 0;
		return mul(mul(fac[n],invfac[m]),invfac[n-m]);
	}

	void math_init()
	{
		fac[0]=invfac[0]=1;
		rep(i,1,N) fac[i]=mul(fac[i-1],i);
		invfac[N]=getinv(fac[N]);
		per(i,N-1,1) invfac[i]=mul(invfac[i+1],i+1);
	}
	#undef N
}
using namespace My_Math;

int n,a[1010],b[1010];

int main()
{
	int T=read();
	while (T--)
	{
		n=read();
		rep(i,1,n) {a[i]=read(),b[i]=read();}
		int ok=1;
		rep(i,1,n)
			if ((a[i]<a[i-1]) || (b[i]<b[i-1]) || (a[i]-a[i-1]<b[i]-b[i-1]) || (a[i]<b[i]))
			{
				ok=0;break;
			}
		if (ok) puts("YES");else puts("NO");
	}
	return 0;
}

B

最优策略是所有\(\geq x\)的人都来做贡献,帮助那些最容易到达\(x\)的人。也就是将\(a_i\)排序后,操作区间一定是一段后缀,枚举之后check即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double db;
typedef vector<int> vi;
typedef pair<int,int> pii;
const int N=100000;
const db pi=acos(-1.0);
#define lowbit(x) (x)&(-x)
#define sqr(x) (x)*(x)
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define go(u,i) for (register int i=head[u],v=sq[i].to;i;i=sq[i].nxt,v=sq[i].to)
#define fir first
#define sec second
#define mkp make_pair
#define pb push_back
#define maxd 998244353
#define eps 1e-8
#define int long long
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
    while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
    return x*f;
}

namespace My_Math{
	#define N 100000

	int fac[N+100],invfac[N+100];

	int add(int x,int y) {return x+y>=maxd?x+y-maxd:x+y;}
	int dec(int x,int y) {return x<y?x-y+maxd:x-y;}
	int mul(int x,int y) {return 1ll*x*y%maxd;}
	ll qpow(ll x,int y)
	{
		ll ans=1;
		while (y)
		{
			if (y&1) ans=mul(ans,x);
			x=mul(x,x);y>>=1;
		}
		return ans;
	}
	int getinv(int x) {return qpow(x,maxd-2);}

	int C(int n,int m)
	{
		if ((n<m) || (n<0) || (m<0)) return 0;
		return mul(mul(fac[n],invfac[m]),invfac[n-m]);
	}

	void math_init()
	{
		fac[0]=invfac[0]=1;
		rep(i,1,N) fac[i]=mul(fac[i-1],i);
		invfac[N]=getinv(fac[N]);
		per(i,N-1,1) invfac[i]=mul(invfac[i+1],i+1);
	}
	#undef N
}
using namespace My_Math;

int n,m,a[100100];

signed main()
{
	int T=read();
	while (T--)
	{
		n=read();m=read();
		rep(i,1,n) a[i]=read();
		sort(a+1,a+1+n);reverse(a+1,a+1+n);
		ll sum=0;int pos=0;
		rep(i,1,n)
		{
			if (a[i]>=m) sum+=a[i];
			else {pos=i;break;}
		}
		if (!pos) {printf("%lld\n",n);continue;}
		int ans=pos-1;
		rep(i,pos,n)
		{
			sum+=a[i];
			if (sum>=i*m) ans=max(ans,i);
		}
		printf("%lld\n",ans);
	}
	return 0;
}

C

显然我们希望爆炸所产生的伤害尽可能的大。也就是希望每一只怪兽都受到爆炸伤害。但是需要有一只怪兽作为“引信”,它是无法受到爆炸伤害的。

预处理出所有怪兽受到爆炸伤害后还需要打多少下,再枚举作为“引信”的怪兽即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double db;
typedef vector<int> vi;
typedef pair<int,int> pii;
const int N=300000+100;
const db pi=acos(-1.0);
#define lowbit(x) (x)&(-x)
#define sqr(x) (x)*(x)
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define go(u,i) for (register int i=head[u],v=sq[i].to;i;i=sq[i].nxt,v=sq[i].to)
#define fir first
#define sec second
#define mkp make_pair
#define pb push_back
#define maxd 998244353
#define eps 1e-8
#define int long long
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
    while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
    return x*f;
}

namespace My_Math{
	#define N 100000

	int fac[N+100],invfac[N+100];

	int add(int x,int y) {return x+y>=maxd?x+y-maxd:x+y;}
	int dec(int x,int y) {return x<y?x-y+maxd:x-y;}
	int mul(int x,int y) {return 1ll*x*y%maxd;}
	ll qpow(ll x,int y)
	{
		ll ans=1;
		while (y)
		{
			if (y&1) ans=mul(ans,x);
			x=mul(x,x);y>>=1;
		}
		return ans;
	}
	int getinv(int x) {return qpow(x,maxd-2);}

	int C(int n,int m)
	{
		if ((n<m) || (n<0) || (m<0)) return 0;
		return mul(mul(fac[n],invfac[m]),invfac[n-m]);
	}

	void math_init()
	{
		fac[0]=invfac[0]=1;
		rep(i,1,N) fac[i]=mul(fac[i-1],i);
		invfac[N]=getinv(fac[N]);
		per(i,N-1,1) invfac[i]=mul(invfac[i+1],i+1);
	}
	#undef N
}
using namespace My_Math;

int n,a[N],b[N],c[N];

signed main()
{
	int T=read();
	while (T--)
	{
		n=read();
		rep(i,1,n) {a[i]=read();b[i]=read();}
		ll sum=0,ans=1e18;
		rep(i,1,n)
		{
			int pre=i-1;
			if (!pre) pre+=n;
			c[i]=max(0ll,a[i]-b[pre]);sum+=c[i];
		}
		rep(i,1,n) ans=min(ans,sum-c[i]+a[i]);
		printf("%lld\n",ans);
	}
	return 0;
}

D

打个\(n=5\)的序列看看:

\[1\ 2\ 1\ 3\ 1\ 4\ 1\ 5\ 2\ 3\ 2\ 4\ 2\ 5\ 3\ 4\ 3\ 5\ 4\ 5\ 1 \]

加上换行

1 2 1 3 1 4 1 5 
2 3 2 4 2 5
3 4 3 5
4 5
1

暴力模拟这个序列的生成过程即可:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double db;
typedef vector<int> vi;
typedef pair<int,int> pii;
const int N=100000;
const db pi=acos(-1.0);
#define lowbit(x) (x)&(-x)
#define sqr(x) (x)*(x)
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define go(u,i) for (register int i=head[u],v=sq[i].to;i;i=sq[i].nxt,v=sq[i].to)
#define fir first
#define sec second
#define mkp make_pair
#define pb push_back
#define maxd 998244353
#define eps 1e-8
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
    while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
    return x*f;
}

namespace My_Math{
	#define N 100000

	int fac[N+100],invfac[N+100];

	int add(int x,int y) {return x+y>=maxd?x+y-maxd:x+y;}
	int dec(int x,int y) {return x<y?x-y+maxd:x-y;}
	int mul(int x,int y) {return 1ll*x*y%maxd;}
	ll qpow(ll x,int y)
	{
		ll ans=1;
		while (y)
		{
			if (y&1) ans=mul(ans,x);
			x=mul(x,x);y>>=1;
		}
		return ans;
	}
	int getinv(int x) {return qpow(x,maxd-2);}

	int C(int n,int m)
	{
		if ((n<m) || (n<0) || (m<0)) return 0;
		return mul(mul(fac[n],invfac[m]),invfac[n-m]);
	}

	void math_init()
	{
		fac[0]=invfac[0]=1;
		rep(i,1,N) fac[i]=mul(fac[i-1],i);
		invfac[N]=getinv(fac[N]);
		per(i,N-1,1) invfac[i]=mul(invfac[i+1],i+1);
	}
	#undef N
}
using namespace My_Math;

#define int long long

int n,a[400400];
ll L,R;

void out(ll l,ll r,ll L,ll R,int n,int id)
{
	ll nowl=max(l,L),nowr=min(r,R);
	if (nowl>nowr) return;
	ll bas=l-1;
	nowl-=bas;nowr-=bas;
	rep(i,nowl,nowr) 
	{
		int now;
		if (i&1) now=id;
		else now=(i>>1)+id;
		printf("%lld ",now);
	}
}	

signed main()
{
	int T=read();
	while (T--)
	{
		n=read();
		scanf("%lld%lld",&L,&R);
		ll nowl,nowr=0;
		rep(i,1,n-1)
		{
			int len=((n-i)<<1);
			nowl=nowr+1;nowr=nowl+len-1;
			out(nowl,nowr,L,R,len,i);
		}
		if (1ll*n*(n-1)+1==R) printf("1");
		puts("");
	}
	return 0;
}

E

先给出结论:

  • 对于\(x,y\)的最短路,它一定会经过\(\gcd(x,y)\), 且\(x\to \gcd(x,y)\)的路径上的所有数单调递减,\(\gcd(x,y) \to y\)的路径上的所有数单调递增。

  • 对于一条路径上的数单调递减的路径\(x\to y\),记通过每条边时除去的质数因子为\(p_1,p_2,\cdots,p_k\),则\(p_1,p_2,\cdots,p_k\)的顺序不影响结果。

再给出做法:

预处理出\(D\)的所有质因子,再在\(O(\sqrt D)\)的时间内找到\(D\)的所有因子及其质因数分解。对于每组询问\(x\ y\)拆成\(x\to \gcd(x,y)\)\(gcd(x,y)\to y\),对于每个询问分别算出贡献即可。假设在这条路径上质因数\(p_i\)需要减少/增加\(a_i\)个,则答案为\(\frac{(\sum a_i)!}{\prod{a_i!}}\).

最后给出xjb证明(以下整理自cf评论区)

\(x=\prod_{i=1}^mp_i^{\alpha_i}(\alpha\geq 0),y=xp_i\)\(w(x,y)=\sigma_0(y)-\sigma_0(x)=(\alpha_1+1)(\alpha_2+1)\cdots(\alpha_{i-1}+1)(\alpha_{i+1}+1)\cdots(\alpha_m+1)=\frac{\sigma_0(x)}{\alpha_i+1}\)

  • 结论1:在路径\(x\to y\)中,对每个质因数\(p_i\),不可能出现同时加上和减去这个质因数的情况。

不失一般性的,我们可以把这条路径看成\(x\to xp_i\to x_1p_i\to \cdots \to yp_i \to y\).
将其与\(x\to x_1\to \cdots \to y\)进行比较。

除去开头和结尾,均有:\(w(第一种方法)\geq w(第二种方法)\),取到等号当且仅当此时增加/减少的质数就是\(p\).然后又由于第一种方法还有开头和结尾的权值,所以一定没有第二种方法优。

这个结论把可能的路径情况分为了两大类,接下来只要对这两大类分类讨论即可。

  • 结论2:路径\(x\to \gcd(x,y)\to y\)\(y\to \mathrm{lcm}(x,y) \to y\)更优。

看起来十分显然

\(a=\gcd(x,y),b=\mathrm{lcm}(x,y)\),则\(x=ac_1,y=ac_2,b=ac_1c_2\)

不妨设\(c_1,c_2\)均为质数。将两种方法的权值相减

\[\begin{aligned} (&2\sigma_0(ac_1c_2)-\sigma_0(ac_1)-\sigma_0(ac_2))-(\sigma_0(ac_1)+\sigma_0(ac_2)-2\sigma_0(a))\\ =&2((\sigma_0(ac_1c_2)-\sigma_0(ac_1))-(\sigma_0(ac_2)-\sigma_0(a)) \end{aligned} \]

由于\(c_1\neq c_2\)所以差值\(>0\),也就是第二种方法的权值和一定大于第一种。结论得证。

  • 结论3:在路径上的数单调递减的路径\(x\to y\)上,每次减少的质数的顺序不影响答案。

这个结论比较好证:无论其顺序如何,路径的权值和永远是\(\sigma_0(x)-\sigma_0(y)\).所以最后的方案数会是一个类似于组合数的东西。

由于是考场上rush出来的写的比较丑还请见谅qwq

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double db;
typedef vector<int> vi;
typedef pair<int,int> pii;
const int N=100000;
const db pi=acos(-1.0);
#define lowbit(x) (x)&(-x)
#define sqr(x) (x)*(x)
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define go(u,i) for (register int i=head[u],v=sq[i].to;i;i=sq[i].nxt,v=sq[i].to)
#define fir first
#define sec second
#define mkp make_pair
#define pb push_back
#define maxd 998244353
#define eps 1e-8
#define int long long 
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
    while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
    return x*f;
}

namespace My_Math{
	#define N 100000

	int fac[N+100],invfac[N+100];

	int add(int x,int y) {return x+y>=maxd?x+y-maxd:x+y;}
	int dec(int x,int y) {return x<y?x-y+maxd:x-y;}
	int mul(int x,int y) {return 1ll*x*y%maxd;}
	ll qpow(ll x,int y)
	{
		ll ans=1;
		while (y)
		{
			if (y&1) ans=mul(ans,x);
			x=mul(x,x);y>>=1;
		}
		return ans;
	}
	int getinv(int x) {return qpow(x,maxd-2);}

	int C(int n,int m)
	{
		if ((n<m) || (n<0) || (m<0)) return 0;
		return mul(mul(fac[n],invfac[m]),invfac[n-m]);
	}

	void math_init()
	{
		fac[0]=invfac[0]=1;
		rep(i,1,N) fac[i]=mul(fac[i-1],i);
		invfac[N]=getinv(fac[N]);
		per(i,N-1,1) invfac[i]=mul(invfac[i+1],i+1);
	}
	#undef N
}
using namespace My_Math;

map<int,vi> mp;
int n,Len;

void sieve(int n)
{
	vi c,p;
	int tmp=n;
	for (int i=2;i*i<=n;i++)
	{
		if (n%i) continue;
		int cnt=0;
		while (n%i==0) {n/=i;cnt++;}
		p.pb(i);c.pb(cnt);
	}
	if (n>1) {p.pb(n);c.pb(1);}
	n=tmp;Len=p.size();
	for (int i=1;i*i<=n;i++)
	{
		if (n%i) continue;
		vi now;now.clear();
		int x=i;now.resize(Len);
		rep(j,0,Len-1)
		{
			if (x%p[j]) continue;
			while (x%p[j]==0) {x/=p[j];now[j]++;}
		}
		mp[i]=now;
		if (i*i!=n)
		{
			rep(j,0,Len-1) now[j]=c[j]-now[j];
			mp[n/i]=now;
		}
	}
}

int calc(int x,int y)
{
	int sum=0;
	rep(i,0,Len-1) sum+=(mp[x][i]-mp[y][i]);
	sum=fac[sum];
	rep(i,0,Len-1) sum=mul(sum,invfac[mp[x][i]-mp[y][i]]);
	return sum;
}

int solve(int x,int y)
{
	int z=__gcd(x,y);
	return mul(calc(x,z),calc(y,z));
}

signed main()
{
	math_init();
	n=read();
	sieve(n);
	int q=read();
	while (q--)
	{
		int x=read(),y=read();
		printf("%lld\n",solve(x,y));
	}
	return 0;
}

F

一个经典的dp是记\(f_{i,j}\)为考虑了\(a\)的前\(i\)个数,已经有了\(b\)的前\(j\)位时的方案数,转移则是直接根据\(a_i\)是否保留,以及\(a_i\)\(b_j\)的大小关系进行转移。

考虑\(i\)相同时的所有状态,不难发现转移可以看做一个前缀加和一个后缀加(可能还会存在当\(a_i=b_j\)时的一个单点修改)可以直接线段树维护。具体转移可以看代码。

#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<bitset>
#include<math.h>
#include<stack>
#include<queue>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double db;
typedef vector<int> vi;
typedef pair<int,int> pii;
const int N=500000+500;
const db pi=acos(-1.0);
#define lowbit(x) (x)&(-x)
#define sqr(x) (x)*(x)
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define go(u,i) for (register int i=head[u],v=sq[i].to;i;i=sq[i].nxt,v=sq[i].to)
#define fir first
#define sec second
#define mkp make_pair
#define pb push_back
#define maxd 998244353
#define eps 1e-8
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
    while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
    return x*f;
}

namespace My_Math{
	#define N 100000

	int fac[N+100],invfac[N+100];

	int add(int x,int y) {return x+y>=maxd?x+y-maxd:x+y;}
	int dec(int x,int y) {return x<y?x-y+maxd:x-y;}
	int mul(int x,int y) {return 1ll*x*y%maxd;}
	ll qpow(ll x,int y)
	{
		ll ans=1;
		while (y)
		{
			if (y&1) ans=mul(ans,x);
			x=mul(x,x);y>>=1;
		}
		return ans;
	}
	int getinv(int x) {return qpow(x,maxd-2);}

	int C(int n,int m)
	{
		if ((n<m) || (n<0) || (m<0)) return 0;
		return mul(mul(fac[n],invfac[m]),invfac[n-m]);
	}

	void math_init()
	{
		fac[0]=invfac[0]=1;
		rep(i,1,N) fac[i]=mul(fac[i-1],i);
		invfac[N]=getinv(fac[N]);
		per(i,N-1,1) invfac[i]=mul(invfac[i+1],i+1);
	}
	#undef N
}
using namespace My_Math;

namespace Segment_Tree{
	
	ll seg[N<<2],tag[N<<2];
	
	void build(int id,int l,int r)
	{
		seg[id]=2e18;tag[id]=0;
		if (l==r) 
		{
			if (!l) seg[id]=0;
			return;
		} 
		int mid=(l+r)>>1;
		build(id<<1,l,mid);build(id<<1|1,mid+1,r);
	}
	
	void pushdown(int id)
	{
		if (tag[id])
		{
			seg[id<<1]+=tag[id];seg[id<<1|1]+=tag[id];
			tag[id<<1]+=tag[id];tag[id<<1|1]+=tag[id];
			tag[id]=0;
		}
	}
	
	void modify(int id,int l,int r,int ql,int qr,ll val)
	{
		if ((l>=ql) && (r<=qr))
		{
			seg[id]+=val;tag[id]+=val;
			return;
		}
		int mid=(l+r)>>1;pushdown(id);
		if (ql<=mid) modify(id<<1,l,mid,ql,qr,val);
		if (qr>mid) modify(id<<1|1,mid+1,r,ql,qr,val);
	}
	
	ll query(int id,int l,int r,int pos)
	{
		if (l==r) return seg[id];
		int mid=(l+r)>>1;pushdown(id);
		if (pos<=mid) return query(id<<1,l,mid,pos);
		else return query(id<<1|1,mid+1,r,pos);
	}
}
using namespace Segment_Tree;

int n,m,a[N],p[N],b[N];

int main()
{
	n=read();
	rep(i,1,n) a[i]=read();
	rep(i,1,n) p[i]=read();
	m=read();
	rep(i,1,m) b[i]=read();b[m+1]=2e9;
	build(1,0,m);
	rep(i,1,n)
	{
		int j=lower_bound(b+1,b+1+m,a[i])-b;
		if (a[i]==b[j])
		{
			ll x=query(1,0,m,j-1),pre=query(1,0,m,j),y=pre+min(p[i],0);
			ll cost=min(x,y);
			modify(1,0,m,j,j,cost-pre);
			modify(1,0,m,0,j-1,p[i]);
			modify(1,0,m,j+1,m,min(p[i],0));
		}
		else
		{
			modify(1,0,m,0,j-1,p[i]);
			modify(1,0,m,j,m,min(p[i],0));
		} 
	}
	ll ans=query(1,0,m,m);
	if (ans<=1e15) printf("YES\n%lld",ans);
	else printf("NO");
	return 0;
}

G

套路题,可惜比赛时没时间了。

看见不能用kmp做的匹配问题就考虑FFT,定义匹配函数为\(f_i=\sum_{j=0}^i(s_j-t_{i-j})^2(p_{s_j}-t_{i-j})^2\),把\(f_i\)看成是关于\(t_{i-j}\)的函数后展开,做五遍多项式乘法即可。

#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<bitset>
#include<math.h>
#include<stack>
#include<queue>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double db;
typedef vector<int> vi;
typedef pair<int,int> pii;
const int N=200000+100;
const db pi=acos(-1.0);
#define lowbit(x) (x)&(-x)
#define sqr(x) (x)*(x)
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define go(u,i) for (register int i=head[u],v=sq[i].to;i;i=sq[i].nxt,v=sq[i].to)
#define fir first
#define sec second
#define mkp make_pair
#define pb push_back
#define maxd 998244353
#define eps 1e-8
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
    while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
    return x*f;
}

namespace My_Math{
	#define N 100000

	int fac[N+100],invfac[N+100];

	int add(int x,int y) {return x+y>=maxd?x+y-maxd:x+y;}
	int dec(int x,int y) {return x<y?x-y+maxd:x-y;}
	int mul(int x,int y) {return 1ll*x*y%maxd;}
	ll qpow(ll x,int y)
	{
		ll ans=1;
		while (y)
		{
			if (y&1) ans=mul(ans,x);
			x=mul(x,x);y>>=1;
		}
		return ans;
	}
	int getinv(int x) {return qpow(x,maxd-2);}

	void math_init()
	{
		fac[0]=invfac[0]=1;
		rep(i,1,N) fac[i]=mul(fac[i-1],i);
		invfac[N]=getinv(fac[N]);
		per(i,N-1,1) invfac[i]=mul(invfac[i+1],i+1);
	}
	#undef N
}
using namespace My_Math;

namespace polynomial{
	struct complex{
		double x,y;
		complex (double _x=0.0,double _y=0.0) {x=_x;y=_y;}
	};
	
	complex operator +(complex a,complex b) {return complex(a.x+b.x,a.y+b.y);}
	complex operator -(complex a,complex b) {return complex(a.x-b.x,a.y-b.y);}
	complex operator *(complex a,complex b) {return complex(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
	complex operator *(complex a,int b) {return complex(a.x*b,a.y*b);}
	int r[N<<2];
	int calcr(int len)
	{
		int lim=1,cnt=0;
		while (lim<len) {lim<<=1;cnt++;}
		rep(i,0,lim-1) 
			r[i]=(r[i>>1]>>1)|((i&1)<<(cnt-1));
		return lim;
	}
	
	void fft(int lim,complex *a,int typ)
	{
		rep(i,0,lim-1)
			if (i<r[i]) swap(a[i],a[r[i]]);
		for (int mid=1;mid<lim;mid<<=1)
		{
			complex wn=complex(cos(pi/mid),sin(pi/mid)*typ);
			int len=(mid<<1);
			for (int sta=0;sta<lim;sta+=len)
			{
				complex w=complex(1,0);
				for (int j=0;j<mid;j++,w=w*wn)
				{
					complex x=a[j+sta],y=a[j+sta+mid]*w;
					a[j+sta]=x+y;a[j+sta+mid]=x-y;
				}
			}
		}
		if (typ==-1)
			rep(i,0,lim-1) a[i].x/=lim;
	}
}
using namespace polynomial;

int n,m,a[N],b[N],p[30];
complex A[N<<2],B[N<<2],C[N<<2],emp=complex(0,0);
char s[N];
ll sum[N];

int main()
{
	rep(i,1,26) p[i]=read();
	scanf("%s",s);
	n=strlen(s);
	rep(i,0,n-1) a[i]=s[i]-'a'+1;
	reverse(a,a+n);
	scanf("%s",s);
	m=strlen(s);
	rep(i,0,m-1) b[i]=s[i]-'a'+1;
	int lim=calcr(m<<1);
	rep(i,0,n-1) A[i]=complex(a[i]*a[i]*p[a[i]]*p[a[i]],0);
	rep(i,0,m-1) B[i]=complex(1,0);
	fft(lim,A,1);fft(lim,B,1);
	rep(i,0,lim-1) C[i]=C[i]+A[i]*B[i];
	rep(i,0,lim-1) A[i]=B[i]=emp;
	rep(i,0,n-1) A[i]=complex(a[i]*p[a[i]]*(a[i]+p[a[i]])*(-2),0);
	rep(i,0,m-1) B[i]=complex(b[i],0);
	fft(lim,A,1);fft(lim,B,1);
	rep(i,0,lim-1) C[i]=C[i]+A[i]*B[i];
	rep(i,0,lim-1) A[i]=B[i]=emp;
	rep(i,0,n-1) A[i]=complex(a[i]*a[i]+a[i]*p[a[i]]*4+p[a[i]]*p[a[i]],0);
	rep(i,0,m-1) B[i]=complex(b[i]*b[i],0);
	fft(lim,A,1);fft(lim,B,1);
	rep(i,0,lim-1) C[i]=C[i]+A[i]*B[i];
	rep(i,0,lim-1) A[i]=B[i]=0;
	rep(i,0,n-1) A[i]=complex((a[i]+p[a[i]])*(-2),0);
	rep(i,0,m-1) B[i]=complex(b[i]*b[i]*b[i],0);
	fft(lim,A,1);fft(lim,B,1);
	rep(i,0,lim-1) C[i]=C[i]+A[i]*B[i];
	rep(i,0,lim-1) A[i]=B[i]=emp;
	rep(i,0,n-1) A[i]=complex(1,0);
	rep(i,0,m-1) B[i]=complex(b[i]*b[i]*b[i]*b[i],0);
	fft(lim,A,1);fft(lim,B,1);
	rep(i,0,lim-1) C[i]=C[i]+A[i]*B[i];
	fft(lim,C,-1);
	rep(i,n-1,m-1)
	{
		if (fabs(C[i].x)+0.5<1) putchar('1');
		else putchar('0');
	}
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/encodetalker/p/12684873.html