• 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);continue;}
    		int ans=pos-1;
    		rep(i,pos,n)
    		{
    			sum+=a[i];
    			if (sum>=i*m) ans=max(ans,i);
    		}
    		printf("%lld
    ",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
    ",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 o gcd(x,y))的路径上的所有数单调递减,(gcd(x,y) o y)的路径上的所有数单调递增。

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

    再给出做法:

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

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

    (x=prod_{i=1}^mp_i^{alpha_i}(alphageq 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 o y)中,对每个质因数(p_i),不可能出现同时加上和减去这个质因数的情况。

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

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

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

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

    看起来十分显然

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

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

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

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

    • 结论3:在路径上的数单调递减的路径(x o 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
    ",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
    %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;
    }
    
  • 相关阅读:
    (译) 在AngularJS中使用的表单验证功能
    TypeError: Cannot red property 'style' of null 错误解决
    Velocity CheckingForNull
    推荐系统(Recommendation system )介绍
    python 时间戳和日期相互转换
    Markdown 语法的简要规则
    mpvue + 微信小程序 picker 实现自定义多级联动 超简洁
    微信小程序 上传图片并等比列压缩到指定大小
    vue路由的两种模式,hash与history的区别
    修改浏览器url地址或者参数 , 实现不刷新页面
  • 原文地址:https://www.cnblogs.com/encodetalker/p/12684873.html
Copyright © 2020-2023  润新知