多项式 - 除法与取模

一类问题:给定一个 \(n\) 次多项式 \(F(x)\) 和一个 \(m\) 次多项式 \(G(x)\),请求出多项式 \(Q(x)\),\(R(x)\),满足以下条件:

  • \(Q(x)\) 次数为 \(n?m\),\(R(x)\) 次数小于 \(m\)
  • \(F(x)=Q(x)?G(x)+R(x)\)

所有的运算在模 \(998244353\) 意义下进行。

 

多项式求逆

放一篇博客。直接做多项式的除法是无从下手的,或者说没有很优秀的方法可以优化它的复杂度。

然而逆元是个很方便的东西,乘法和除法是一对互逆运算,于是想到可以找到多项式 \(G(x)\) 的逆元 \(G^{-1}(x)\) 而转变成 \(NTT\) 解决的多项式乘问题。

我们设 \(B(x)\) 是 \(A(x)\) 在模 \(x^n\) 意义下的逆元,有 \(A(x)B(x) \equiv 1 (mod\ x^n)\),下面列出几条规律。

当 \(n=1\) 时,\(A(x)=c\),\(c\) 是一个常数,则 \(B(x)=c^{-1}\)。

当 \(n>1\) 时,假设在 \((mod\ x^{\lceil \frac{n}{2} \rceil)}\) 意义下 \(A(x)\) 的逆元是 \(B^′(x)\),并且我们已经求出,那么:\(A(x)B^′(x) \equiv 1(mod\ x^{\lceil \frac{n}{2} \rceil})\)

而且在 \(mod\ x^{\lceil \frac{n}{2} \rceil}\) 下也有:\(A(x)B(x) \equiv 1(mod\ x^{\lceil \frac{n}{2} \rceil})\)

然后就可以得到:\(B(x)?B^′(x) \equiv 0(mod\ x^{\lceil \frac{n}{2} \rceil})\)

两边平方 \(B^2(x)?2B^′(x)B(x)+B^{′2}(x) \equiv 0(mod\ x^n)\)

然后同时乘上 \(A(x)\),移项可以得到 \(B(x) \equiv 2B^′(x)?A(x)B^{′2}(x)(mod\ x^n)\),由此式即可得到逆元。

 

\(Code:\)

#include <cmath>
#include <queue>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

typedef long long u64;

const int mod = 998244353;
const int maxn = 600000 + 10;
int n, r[maxn], bit[maxn]; u64 f[maxn], inv[maxn], tmp[maxn];

inline int read() {
  register char ch = 0; register int w = 0, x = 0;
  while( !isdigit(ch) ) w |= (ch == ‘-‘), ch = getchar();
  while( isdigit(ch) ) x = (x * 10) + (ch ^ 48), ch = getchar();
  return w ? -x : x;
}

inline u64 Fast_pow(u64 a, int p) {
  u64 x = a, ans = 1ll;
  for( ; p; x = x * x % mod, p = p >> 1) if( p & 1 ) ans = x * ans % mod;
  return ans;
}

inline void Number_theory_transform(u64 *a, int limit, int type) {
  int rado = bit[limit];
  for(int i = 0; i < limit; ++i) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (rado - 1));
  for(int i = 0; i < limit; ++i) if( i < r[i] ) swap(a[i], a[r[i]]);
  for(int mid = 1; mid < limit; mid = mid << 1) {
    u64 Base_p = Fast_pow(3ll, (mod - 1) / (mid << 1));
    if( type == -1 ) Base_p = Fast_pow(Base_p, mod - 2);
    for(int l = 0, length = mid << 1; l < limit; l = l + length) {
      for(int k = 0, p = 1; k < mid; ++k, p = p * Base_p % mod) {
        u64 x = a[l + k], y = p * a[l + mid + k] % mod;
        a[l + k] = (x + y) % mod, a[l + mid + k] = (x - y + mod) % mod;
      }
    }
  }
  if( type == -1 ) for(int i = 0; i < limit; ++i) a[i] = a[i] * Fast_pow(limit, mod - 2) % mod;
}

inline void Inverse_transform(u64 *a, u64 *b, int limit) {
  if( limit == 1 ) { b[0] = Fast_pow(a[0], mod - 2); return ; }
  Inverse_transform(a, b, (limit + 1) >> 1);
  int len = limit << 1;
  for(int i = 0; i < limit; ++i) tmp[i] = a[i];
  for(int i = limit; i < len; ++i) tmp[i] = 0;
  Number_theory_transform(tmp, len, 1);
  Number_theory_transform(b, len, 1);
  for(int i = 0; i < len; ++i) b[i] = (2 * b[i] % mod - (b[i] * b[i] % mod) * tmp[i] % mod + mod) % mod;
  Number_theory_transform(b, len, -1);
  for(int i = limit; i < len; ++i) b[i] = 0;
}

int main(int argc, char const *argv[])
{
  freopen("..\\nanjolno.in", "r", stdin);
  freopen("..\\nanjolno.out", "w", stdout);

  scanf("%d", &n);
  for(int i = 0; i < n; ++i) f[i] = read();
  int limit = 1, rado = 0;
  while( limit <= n ) limit = limit << 1, ++rado;
  for(int i = 0; i < 20; ++i) bit[1 << i] = i;
  Inverse_transform(f, inv, limit);
  for(int i = 0; i < n; ++i) printf("%lld ", inv[i]);

  fclose(stdin), fclose(stdout);
  return 0;
}

 

多项式除法与取模

有了逆元,事情就简单了很多,但是依然只是个开始。

考虑最初的式子 \(F(x)=Q(x)?G(x)+R(x)\),要求得 \(Q(x)\) 最大的障碍就是 \(R(x)\),于是就想把 \(R(x)\) 通过一定的方法试试能不能消掉。

把上式的 \(x\) 全部用 \(\frac{1}{x}\) 来替代,然后等式两边同时乘上 \(x^n\),这意味着对于一个多项式其系数会全部反转,等式变成了:

\(F^R(x)=Q^R(x)G^R(x)+x^{n?m+1}R^R(x)\)

这样,\(Q(x)\) 是要求的元素之一,反转后次数仍然不高于 \(n?m\),而 \(x^{n?m+1}R(x)\) 这个部分的最低次项高于 \(n?m\),放到 \(mod\ x^{n?m+1}\) 意义下,\(R(x)\) 的影响被消除了。

于是 \(F^R(x)=Q^R(x)G^R(x)(mod\ x^{n?m+1})\)。

这样就只需要求一个 \(G^R(x)\) 的逆元,就可以利用多项式常用的倍增方法得到 \(Q^R(x)\),那么显然,\(R(x)=F(x)-G(x)Q(x)\)。

 

\(Code:\)

inline int Limit(int len) { for(int i = 1; ; i = i << 1) if( i > len ) return i; }

inline void Multiply_transform(u64 *a, u64 *b, u64 *c, int len_1, int len_2) {
  int len = Limit(len_1 + len_2);
  for(int i = 0; i <= len_1; ++i) tmp_1[i] = a[i];
  for(int i = 0; i <= len_2; ++i) tmp_2[i] = b[i];
  Number_theory_transform(tmp_1, len, 1);
  Number_theory_transform(tmp_2, len, 1);
  for(int i = 0; i < len; ++i) c[i] = tmp_1[i] * tmp_2[i] % mod, tmp_1[i] = tmp_2[i] = 0;
  Number_theory_transform(c, len, -1);
}

int main(int argc, char const *argv[])
{
  for(int i = 0; i < 20; ++i) bit[1 << i] = i;
  scanf("%d%d", &n, &m);
  for(int i = 0; i <= n; ++i) f_1[i] = read();
  for(int i = 0; i <= m; ++i) f_2[i] = read();
  reverse(f_1, f_1 + n + 1), reverse(f_2, f_2 + m + 1);
  Inverse_transform(f_2, inv, Limit(n - m));
  Multiply_transform(f_1, inv, ans, n - m, n - m);
  reverse(ans, ans + n - m + 1);
  for(int i = 0; i <= n - m; ++i) printf("%lld ", ans[i]); printf("\n");
  reverse(f_1, f_1 + n + 1), reverse(f_2, f_2 + m + 1);
  Multiply_transform(ans, f_2, mul, n - m, m);
  for(int i = 0; i < m; ++i) printf("%lld ", (f_1[i] - mul[i] + mod) % mod); printf("\n");

  return 0;
}

 

                     与君相遇,乃思长生。

原文地址:https://www.cnblogs.com/nanjoqin/p/10358417.html

时间: 2024-07-30 16:39:45

多项式 - 除法与取模的相关文章

通过逆元实现大数据除法的取模

当题目中数据较大,而且计算中出现过除法的时候.往往取模会出错 当计算 (A/B) % c    等价于  (A*B1)% c 其中 B1 是 B 的逆元. 那么逆元如何求呢. 先给出逆元的定义 a*x ≡1 (mod n)  ,如果x是方程的解,则x称作 a 关于模 n 的逆. a的逆元存在是有条件的: 方程ax-ny==1 要有解 则 1必须是gcd(a,n)的倍数 ,因此,a和n必须素质, 即 gcd(a,n)==1 在这个前提下 ax≡1(mod n) 只有唯一解. 现在我们来证明上面的结

Divide two numbers,两数相除求商,不能用乘法,除法,取模运算

问题描述:求商,不能用乘法,除法,取模运算. 算法思路:不能用除法,那只能用减法,但是用减法,超时.可以用位移运算,每次除数左移,相当于2倍. 1 public class DividTwoIntegers { 2 public int divide(int dividend, int divisor) 3 { 4 if(divisor == 0) return Integer.MAX_VALUE; 5 if(divisor == -1 && dividend == Integer.MIN

3.29省选模拟赛 除法与取模 dp+组合计数

LINK:除法与取模 鬼题.不过50分很好写.考虑不带除法的时候 其实是一个dp的组合计数. 考虑带除法的时候需要状压一下除法操作. 因为除法操作是不受x的大小影响的 所以要状压这个除法操作. 直接采用二进制状压是不明智的 2的个数最多为13个 2^13也同样到达了1e4的复杂度. 考虑 hash状压 即 2的个数有x个 那么我们就有状态w表示2还有x个. 这样做的原因是把一些相同的东西给合并起来 而并非分散开来.即有多个2直接记录有多少个即可. 可以发现 这样做不同的除数最多只有5个 状态量较

带除法的取模运算

type1 $\frac{x}{y}\%P,其中P是大质数$ 用费马小小定理得: $y^{P-1}\equiv 1(mod P)$ 故: $\frac{x}{y}\%P=\frac{x*y^{P-1}}{y}\%P=x*y^{P-2}\%P$ type2 $\frac{x}{y}\%P,其中x和y可分解质因数$ 我们还是用一些例子来讲比较好一些. 求卡特兰数$\frac{C_{2n}^{n}}{n+1}\%P$ $\frac{C_{2n}^{n}}{n+1}\%P$ $=\frac{(n+2)\

除法运算和取模

package review20140420;/* * 除法和取模(整数除以整数,会出现除数不能为零的异常) */public class Test2 {    //程序的入口    public static void main(String[] args) {        /*定义变量a,b*/        double a=5.2;        double b=3.1;        //除法运算        double div=a/b;        //取模运算      

多项式除法&amp;取模

除法&取模设 $n$ 次多项式 $F(x)$ 和 $m$ 次多项式 $G(x)$ ,求 $n-m$ 次多项式 $Q(x)$ 和 $m-1$ 次多项式 $R(x)$ 满足$$F(x)=G(x)Q(x)+R(x)$$于是我们有 $$F(\frac{1}{x})=G(\frac{1}{x})Q(\frac{1}{x})+R(\frac{1}{x})$$两遍同乘 $x^n$ : $$x^nF(\frac{1}{x})=x^mG(\frac{1}{x})x^{n-m}Q(\frac{1}{x})+x^{n

HDU 5895 Mathematician QSC(矩阵乘法+循环节降幂+除法取模小技巧+快速幂)

传送门:HDU 5895 Mathematician QSC 这是一篇很好的题解,我想讲的他基本都讲了http://blog.csdn.net/queuelovestack/article/details/52577212 [分析]一开始想简单了,对于a^x mod p这种形式的直接用欧拉定理的数论定理降幂了 结果可想而知,肯定错,因为题目并没有保证gcd(x,s+1)=1,而欧拉定理的数论定理是明确规定的 所以得另谋出路 那么网上提供了一种指数循环节降幂的方法 具体证明可以自行从网上找一找 有

除法取模

2016.1.26 在加减乘都有公式方便我们计算时,除法显得有些丧心病狂,(a/b)%m显然不一定等于( (a%m) / (b%m) )%m. 但其实除法取模如果在算法竞赛中遇到一般都会有小技巧来避免这一步,但在这里还是说一下网上的一般处理办法. 那当然就是费马小定理. 在p为素数,b无法被p整除的情况下,有bp-1≡1(mod p) 所以(1/b)*bp-1≡(1/b)(mod p) 即bp-2≡(1/b)(mod p) 于是(a/b)%m就变成了(a*bp-2)%m 而bp-2可以用快速幂解

【转】C/C++除法实现方式及负数取模详解

原帖:http://blog.csdn.net/sonydvd123/article/details/8245057 一.下面的题目你能全做对吗?1.7/4=? 2.7/(-4)=? 3.7%4=? 4.7%(-4)=? 5.(-7)/4=? 6.(-7)%4=? 7.(-7)/(unsigned)4=? 答案: 1 -1 3 3 -1 -3 1073741822 如过你全部答对,你可以无视后面的内容-- 二.除法的取整分类除法的取整分为三类:向上取整.向下取整.向零取整. 1.向上取整:向+∞