多项式[CSP2019模拟-Day6B][欧几里得类算法]

文章目录

题目

在这里插入图片描述

在这里插入图片描述

思路

好像是一个非常套路的思想…
假设 A , B A,B A,B 是我们输入的多项式,可以将其表示为:
A X + B Y = C AX+BY=C AX+BY=C
目标是构造出 X , Y X,Y X,Y 使得 C C C 尽量小
很自然联想到扩欧…
当然在这之前看看题目中的乘法有一些什么性质
可以看作先做多项式相乘再对2取模
于是多项式的交换律,分配律,结合律都有了
这里对2取模加减法时候可以看做异或运算
为了和扩欧扯上关系
我们假设这里 A , B A,B A,B 是可以因式分解的,那我们就是要求出一个类似 g c d ( A , B ) gcd(A,B) gcd(A,B) 的东西
发现这里分解后有些式子也是不能再分解的
那就把他们想象成质数
回顾 E x g c d Exgcd Exgcd

int Exgcd(int a,int b,int& x,int& y){
	if(!b){x=1,y=0;return a;}
	int g=Exgcd(b,a%b,y,x);
	y-=a/b*x;
	return g;
}

a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b)
b x ′ + ( a − ⌊ a b ⌋ ∗ b ) y ′ = g c d ( a , b ) bx'+(a-\lfloor\frac{a}{b}\rfloor*b)y'=gcd(a,b) bx+(abab)y=gcd(a,b)
a y ′ + b ( x ′ − ⌊ a b ⌋ y ′ ) = g c d ( a , b ) ay'+b(x'-\lfloor\frac{a}{b}\rfloor y')=gcd(a,b) ay+b(xbay)=gcd(a,b)

考虑在这里:
A X + B Y = g c d ( A , B ) ( l e n A ≥ l e n B ) AX+BY=gcd(A,B)(len_A\ge len_B) AX+BY=gcd(A,B)(lenAlenB)
A = K B + T A=KB+T A=KB+T
发现 K K K 这里是一个多项式,我们并不好确定最优的 K K K
那就让 K = x l e n A − l e n B K=x^{len_A-len_B} K=xlenAlenB
至少让 A A A 减少一位
T X ′ + B Y ′ = g c d ( A , B ) TX'+BY'=gcd(A,B) TX+BY=gcd(A,B)
( A − K B ) X ′ + B Y ′ = g c d ( A , B ) (A-KB)X'+BY'=gcd(A,B) (AKB)X+BY=gcd(A,B)
A X ′ + B ( Y ′ − K X ′ ) = g c d ( A , B ) AX'+B(Y'-KX')=gcd(A,B) AX+B(YKX)=gcd(A,B)
于是
{ X = X ′ Y = Y ′ − K X ′ \begin{cases} X=X'\\ Y=Y'-KX' \end{cases} {X=XY=YKX

考虑边界情况
就是 A = 0 A=0 A=0 或者 B = 0 B=0 B=0
{ B = 0 X = 1 A = 0 Y = 1 \begin{cases} B=0\quad X=1\\ A=0 \quad Y=1 \end{cases} {B=0X=1A=0Y=1
然后
中间过程用 b i t s e t bitset bitset 实现常数优化
时间复杂度 O ( n 2 k ) O(\frac{n^2}{k}) O(kn2)


你以为就完了吗

这道题还要手动模拟递归…爆栈了

代码

递归版(RE|MLE)

#include<map>
#include<set>
#include<stack>
#include<queue>
#include<vector>
#include<ctime>
#include<bitset>
#include<cmath>
#include<cstdio>
#include<climits>
#include<cstdlib>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
#define ULL unsigned long long
int read(){
	bool f=0;int x=0;char c=getchar();
	while(c<'0'||'9'<c){if(c=='-')f=1;c=getchar();}
	while('0'<=c&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
	return !f?x:-x;
}
#define MAXN 100000
#define INF 0x3f3f3f3f
typedef bitset<MAXN> Poly;
int Siz(Poly X){
	int siz=X.size();
	while(siz>1&&!X.test(siz-1)) siz--;
	return siz;
}
Poly A,B,X,Y;
void Exgcd(int n,int m){
	if(!m){X.set(0);return ;}
	if(!n){Y.set(0);return ;}
	if(n>=m){
		int d=n-m;
		A^=(B<<d);
		while(n&&!A.test(n-1)) n--;
		Exgcd(n,m);
		Y^=(X<<d);
	}
	else{
		int d=m-n;
		B^=(A<<d);
		while(m&&!B.test(m-1)) m--;
		Exgcd(n,m);
		X^=(Y<<d);
	}
	return ;
}
int main(){
	int n=read()+1,m=read()+1;
	for(int i=0;i<n;i++)
		if(read()) A.set(i);
	for(int i=0;i<m;i++)
		if(read()) B.set(i);
	Exgcd(n,m);
	int sx=Siz(X),sy=Siz(Y);
	printf("%d %d\n",sx-1,sy-1);
	for(int i=0;i<sx;i++)
		printf("%d",X.test(i)),putchar(i==sx-1?'\n':' ');
	for(int i=0;i<sy;i++)
		printf("%d",Y.test(i)),putchar(i==sy-1?'\n':' ');
    return 0;
}
/*
4 3
1 0 1 0 1
1 1 0 1

*/

非递归版

#include<map>
#include<set>
#include<stack>
#include<queue>
#include<vector>
#include<ctime>
#include<bitset>
#include<cmath>
#include<cstdio>
#include<climits>
#include<cstdlib>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
#define ULL unsigned long long
int read(){
	bool f=0;int x=0;char c=getchar();
	while(c<'0'||'9'<c){if(c=='-')f=1;c=getchar();}
	while('0'<=c&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
	return !f?x:-x;
}
#define mp make_pair
#define MAXN 100000
#define INF 0x3f3f3f3f
typedef bitset<MAXN> Poly;
int Siz(Poly X){
	int siz=X.size();
	while(siz>1&&!X.test(siz-1)) siz--;
	return siz;
}
Poly A,B,X,Y;
int d[MAXN+5],S[MAXN+5],tp;
void Exgcd(int n,int m){
	while(n&&m){
		if(n>=m){
			int D=n-m;
			A^=(B<<D);
			while(n&&!A.test(n-1)) n--;
			S[++tp]=0,d[tp]=D;
		}
		else{
			int D=m-n;
			B^=(A<<D);
			while(m&&!B.test(m-1)) m--;
			S[++tp]=1,d[tp]=D;
		}
	}
	if(!m) X.set(0);
	if(!n) Y.set(0);
	for(int i=tp;i>=1;i--){
		if(!S[i]) Y^=(X<<d[i]);
		else X^=(Y<<d[i]);
	}
	return ;
}
int main(){
	int n=read()+1,m=read()+1;
	for(int i=0;i<n;i++)
		if(read()) A.set(i);
	for(int i=0;i<m;i++)
		if(read()) B.set(i);
	Exgcd(n,m);
	int sx=Siz(X),sy=Siz(Y);
	printf("%d %d\n",sx-1,sy-1);
	for(int i=0;i<sx;i++)
		printf("%d",X.test(i)),putchar(i==sx-1?'\n':' ');
	for(int i=0;i<sy;i++)
		printf("%d",Y.test(i)),putchar(i==sy-1?'\n':' ');
    return 0;
}
/*
4 3
1 0 1 0 1
1 1 0 1

*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值