题目
思路
好像是一个非常套路的思想…
假设
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′+(a−⌊ba⌋∗b)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(x′−⌊ba⌋y′)=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)(lenA≥lenB)
令
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=xlenA−lenB
至少让
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)
(A−KB)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(Y′−KX′)=gcd(A,B)
于是
{
X
=
X
′
Y
=
Y
′
−
K
X
′
\begin{cases} X=X'\\ Y=Y'-KX' \end{cases}
{X=X′Y=Y′−KX′
考虑边界情况
就是
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
*/