多项式乘法、模除
题意:
给出f(x),g(x),h(x)的 (最高次幂+1)的值,以及它们的各项系数,求f(x)*g(x)/h(x)的余数。
这里多项式的系数只有1或0,
因为题目要求:这里多项式的加减法是将系数相加/减后再模2,这样其实也就可以用异或运算来代替加减法。
思路:
主要在于把除法转化成减法,一次一次减。
用sum[]数组存结果,最高次幂为ls,各项系数存在f[ls-1 … 0]
1 - 计算乘积,
多项式的系数只有1或0,故最高次幂ls = lf + lg -1,f[i]*g[j](i、j为指数的值),相当于位的与运算f[i]&g[j],结果加到x^(i+j)的系数上,即sum[i+j]+=f[i]&g[j];
2 - 计算模除。
sum(x)对h(x)取模,即除以h(x)直到余数小于h(x),此余数即取模的结果,关键在于判别sum(x)、h(x)的大小。
若ls>lh,则sum大;让sum(x)除以h(x):
对h,按次幂由低到高,进行相除运算,h[i]异或到sum[i+ls-lh],即sum[i+d] ^= h[i],然后重新调整sum的最高次幂(while(ls&&!sum[ls-1])-ls)
ls<lh,则h大,得到结果;
若ls=lh,从最高次幂开始逐项比较系数。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 1005;
int cmp(int a[], int la, int b[], int lb){//比较多项式a b的大小
if(la > lb)
return 1;
if(la < lb)
return -1;
for(int i = la - 1; i >= 0; i--){//a b最高次幂相同时,按次幂由高到低顺序逐项比较
if(a[i] && !b[i])
return 1;
else if(!a[i] && b[i])
return -1;
}
return 0;
}
int main(){
int t;
scanf("%d", &t);
while(t--){
int f[N], g[N], h[N];
int lf, lg, lh;
scanf("%d", &lf);//多项式最高次幂
for(int i = lf - 1; i >= 0; i--)//多项式每一项的系数
scanf("%d", &f[i]);
scanf("%d", &lg);
for(int i = lg - 1; i >= 0; i--)
scanf("%d", &g[i]);
scanf("%d", &lh);
for(int i = lh - 1; i >= 0; i--)
scanf("%d", &h[i]);
int sum[N + N], ls = lf + lg - 1;//乘积数组sum、长度初始化
for(int i = 0; i < ls; i++)
sum[i] = 0;
for(int i = 0; i < lf; i++)
for(int j = 0; j < lg; j++)
sum[i + j] ^= (f[i] & g[j]);
//取模
while(cmp(sum, ls, h, lh) >= 0){//当前余数sum不小于h,则继续除以h
int d = ls - lh;
for(int i = 0; i < lh; i++)
sum[i + d] ^= h[i];
while(ls && !sum[ls - 1])
ls--;
}
/*if(ls == 0)//舍去这部分无碍
ls = 1;*/
printf("%d ", ls);
for(int i = ls - 1; i > 0; i--)
printf("%d ", sum[i]);
printf("%d\n", sum[0]);
}
return 0;
}