来记录一下翻车惨案/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
暴力模拟这个序列的生成过程即可:
#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\)均为质数。将两种方法的权值相减
由于\(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;
}