首页 > 其他分享 >【ABC196F】Substring 2(多项式乘法)

【ABC196F】Substring 2(多项式乘法)

时间:2022-10-28 18:34:56浏览次数:68  
标签:11 ... int 多项式 sum Substring 序列 ABC196F

我竟然能在 AT 当场做出 F 题!

哦,是 ABC 啊,没事了。


以下的字符串均从 \(1\) 开始记位。以下设 \(S_i\) 表示字符串 \(S\) 的第 \(i\) 位,\(S(l,r)\) 表示字符串 \(S\) 的第 \(l\) 位到第 \(r\) 位组成的子串,也可以表示字符串 \(S\) 的第 \(l\) 位到第 \(r\) 位组成的序列

设 \(f_{i,j}\) 表示 \(S\) 串从位置 \(i\) 往后 \(j\) 个字符所组成的串 和 \(T\) 串从位置 \(1\) 往后 \(j\) 个字符所组成的串 有多少位不相等,即 \(S(i,i+j-1)\) 和 \(T(1,j)\) 的相差字符个数。

设 \(n=|S|,m=|T|\),那么我们要求的即为:

\[\min\limits_{i=1}^{n-m+1} f_{i,m} \]

显然有转移:

\[\begin{aligned} &f_{i,0}=0\\ &f_{i,j}=f_{i,j-1}+\big[S_{i+j-1}\neq T_{j}\big] \end{aligned} \]

以下定义两个长度相等的序列 \(A,B\) 相加表示 \(A\) 和 \(B\) 各位相加后组成的序列。即如果 \(C=A+B\),那么 \(C_i=A_i+B_i\)。

两个序列相减的定义类似。

一个常数乘一个序列的定义类似。

设序列 \(F_j\) 表示长度为 \(n-m+1\) 的序列 \(f_{1,j},f_{2,j},\cdots,f_{n-m+1,j}\),那么我们要求的就是序列 \(F_m\) 每一位上的值的最小值。

设序列 \(G_j\) 表示长度为 \(n-m+1\) 的序列 \([S_{1+j-1}\neq T_j],[S_{2+j-1}\neq T_j],\cdots,[S_{(n-m+1)+j-1}\neq T_j]\)。

那么根据之前得到的状态转移方程,有:

\[F_{j}=F_{j-1}+G_{j} \]

考虑转化 \(G_j\) :

首先,在 \(a,b\) 都是 \(0\) 或 \(1\) 时,有 \([a\neq b]=a \oplus b\)。(\(\oplus\) 指异或运算)

那么 \(G_j\) 就可以变成序列 \(S_{1+j-1}\oplus T_j,S_{2+j-1}\oplus T_j,\cdots,S_{(n-m+1)+j-1}\oplus T_j\)。

再进一步,当 \(T_j=0\) 时,\(G_j\) 就是 \(S(j,j+n-m)\);当 \(T_j=1\) 时,\(G_j\) 就是 \(S(j,j+n-m)\) 每一位都取反后形成的序列。

更进一步,注意到 \(S(j,j+n-m)\) 每一位都取反后形成的序列其实就是序列 \((11...1)_{n-m+1}-S(j,j+n-m)\)。(这里的 \((11...1)_{n-m+1}\) 指的是一个长度为 \(n-m+1\) 的全为 \(1\) 的序列)。

那么有:

\[F_j=F_{j-1}+ \begin{cases} S(j,j+n-m)&\operatorname{if }T_j=0\\ (11...1)_{n-m+1}-S(j,j+n-m)&\operatorname{if }T_j=1 \end{cases} \]

那么:

\[F_m=\sum_{j=1}^m\begin{cases} S(j,j+n-m)&\operatorname{if }T_j=0\\ (11...1)_{n-m+1}-S(j,j+n-m)&\operatorname{if }T_j=1 \end{cases} \]

我们可以把 \((11...1)_{n-m+1}\) 抽出来最后算:假设 \(T\) 里面有 \(tot\) 位是 \(1\),那么:

\[F_m=tot\times (11...1)_{n-m+1}+\sum_{j=1}^m(-1)^{T_j}S(j,j+n-m) \]

现在我们只需要计算 \(\sum\limits_{j=1}^m(-1)^{T_j}S(j,j+n-m)\) 即可。

这个式子可以理解成为:有一个长度为 \(n-m+1\) 的滑动窗口在 \(S\) 上从左往右移动,每移到某一个位置就把当前记录的答案序列加上/减去滑动窗口内框住的序列。

由于这个滑动窗口是一直在 \(S\) 上的,所以我们可以用多项式来优化这个操作:

设 \(A(x)=S_1x+S_2x^2+\cdots+S_nx^n\)。

我们考虑求出一个多项式 \(C(x)\),然后用 \(C(x)\) 的第 \(m\) 位到第 \(n\) 位(即 \(x^m\) 到 \(x^n\) 的系数)这 \(n-m+1\) 位来表示 \(\sum\limits_{j=1}^m(-1)^{T_j}S(j,j+n-m)\) 计算后得到的长度为 \(n-m+1\) 的序列。(注意,\(C(x)\) 的其他位算出来是啥我们不用管,只用保证这 \(n-m+1\) 位是对的就行)

容易得到:

\[\begin{aligned} C(x)=&\sum_{j=1}^m (-1)^{T_j} \left(S_jx^j+\cdots+S_{j+n-m}x^{j+n-m}\right)x^{m-j}\\ =&\sum_{j=1}^m (-1)^{T_j} A(x) x^{m-j}\\ =&A(x)\times \left(\sum_{j=1}^m (-1)^{T_j} x^{m-j}\right) \end{aligned} \]

乘号两边都是多项式,用 FFT 或 NTT 优化多项式乘法即可。

代码如下:

#include<bits/stdc++.h>

#define LN 22
#define N 1000010
#define INF 0x7fffffff

using namespace std;

namespace modular
{
	const int mod=998244353;
	inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
	inline int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
	inline int mul(int x,int y){return 1ll*x*y%mod;}
}using namespace modular;

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<<1)+(x<<3)+(ch^'0');
		ch=getchar();
	}
	return x*f;
}

inline int poww(int a,int b)
{
    int ans=1;
    while(b)
    {
        if(b&1) ans=mul(ans,a);
        a=mul(a,a);
        b>>=1;
    }
    return ans;
}

int n,m;
int a[N<<3],b[N<<3];
int rev[N<<3],w[LN][N<<3][2];
char s[N],t[N];

void init(int limit)
{
    for(int bit=0,mid=1;mid<limit;bit++,mid<<=1)
    {
        int len=mid<<1;
        int gn=poww(3,(mod-1)/len);
        int ign=poww(gn,mod-2);
        int g=1,ig=1;
        for(int j=0;j<mid;g=mul(g,gn),ig=mul(ig,ign),j++)
            w[bit][j][0]=g,w[bit][j][1]=ig;
    }
}
 
void NTT(int *a,int limit,int opt)
{
    opt=(opt<0);
    for(int i=0;i<limit;i++)
        rev[i]=(rev[i>>1]>>1)|((i&1)*(limit>>1));
    for(int i=0;i<limit;i++)
        if(i<rev[i]) swap(a[i],a[rev[i]]);
    for(int bit=0,mid=1;mid<limit;bit++,mid<<=1)
    {
        for(int i=0,len=mid<<1;i<limit;i+=len)
        {
            for(int j=0;j<mid;j++)
            {
                int x=a[i+j],y=mul(w[bit][j][opt],a[i+mid+j]);
                a[i+j]=add(x,y),a[i+mid+j]=dec(x,y);
            }
        }
    }
    if(opt)
    {
        int tmp=poww(limit,mod-2);
        for(int i=0;i<limit;i++)
            a[i]=mul(a[i],tmp);
    }
}

int main()
{
	scanf("%s%s",s+1,t+1);
	n=strlen(s+1),m=strlen(t+1);
	for(int i=1;i<=n;i++) a[i]=s[i]-'0';
	int tot=0;
	for(int i=1,j=m-1;i<=m;i++,j--)
	{
		if(t[i]=='0') b[j]=1;
		else b[j]=-1,tot++;
	}
	int limit=1;
	while(limit<=(n<<1)) limit<<=1;
	init(limit);
	NTT(a,limit,1),NTT(b,limit,1);
	for(int i=0;i<limit;i++) a[i]=mul(a[i],b[i]);
	NTT(a,limit,-1);
	int ans=INF;
	for(int i=m;i<=n;i++)
		ans=min(ans,add(a[i],tot));
	printf("%d\n",ans);
	return 0;
}
/*
0101010
1010101
*/

标签:11,...,int,多项式,sum,Substring,序列,ABC196F
From: https://www.cnblogs.com/ez-lcw/p/16837049.html

相关文章

  • (算法课)大整数相乘 |向量卷积|多项式相乘| 快速傅里叶变换FFT
    D(1021):很大的ABTimeLimit:1SecMemoryLimit:256MbSubmitted:6Solved:0Description如题,计算AB的值并输出。Input两行,分别代表A和B。A和B......
  • 「ARC151E」Keep Being Substring - 题解
    题意题目链接:Link。有一个序列\(A\)。\(X,Y\)是给定的\(A\)的两个子串,每次可以在\(X\)的开头或末尾增添或删除一个数字,且需满足任意时刻\(X\)非空且为\(A\)的......
  • subStr和subString以及slice的使用和区别
    substr相关使用注意事项第一个参数必须为数值,可正可负可为0为负数则从倒数开始第二个参数是指定长度,默认为到字符串最后如果第一个参数超过字符串的长度,那么会返回......
  • 多项式浅浅浅谈
    由于某种难以言说的原因简而言之就是我比较懒得打\(\LaTeX\)所以进行一下多项式浅浅浅谈郑重声明:本文就是在闲扯不能作为正确的多项式研究资料我推荐算法导论同济出......
  • Python解算多项式
    fromsympyimport*#定义符号变量a,b,c,a1,a2,a3,b1,b2,R,x=symbols("a,b,c,a1,a2,a3,b1,b2,R,x")#公式a=((-(4*R**2*(cos(b1))**2*(sin(b1)*(pow((x**2)*sin(a......
  • Matlab 多项式的根求解
    分享一下通过多种不同的方法计算多项式的根。数值根使用代换法求根特定区间内的根符号根数值根​​roots​​ 函数用于计算系数向量表示的单变量多项式的根。例如,创建一个......
  • LeetCode 76. Minimum Window Substring
    ​​题目​​从第一个字符串中找到最小的子串,让子串中包含第二个字符串中的每一个字符。我的思路来自滑动窗口思想,之前用来做自动摘要的。把第一个字符串中的在第二个字符串......
  • 1010 一元多项式求导(JAVA)
    设计函数求一元多项式的导数。(注:xn(n为整数)的一阶导数为nxn−1。)输入格式:以指数递降方式输入多项式非零项系数和指数(绝对值均为不超过1000的整数)。数字间以空格分隔。输出......
  • 多元线性回归和多项式回归
    多元线性回归直接用sklearn库里的调用代码:https://github.com/xinxuann/MachineLearningNote/blob/main/sklearn-多元线性回归.ipynb多项式回归也是直接调用skl......
  • 多项式的展开公式
    多项式定理二项式定理的展开式富有规律性、美观性,体现了数学的美学文化,而多项式定理为二项式定理的推广。用实际生活中的空盒放球来描述的话,则为:把n个有区别的小球放入......