1. 程式人生 > >九校聯考DAY2T2(中國剩餘定理,積性篩)

九校聯考DAY2T2(中國剩餘定理,積性篩)

題目描述

整除符號為 |,d|n 在計算機語言中可被描述為 n%d == 0。

現有一算式 n|xm - x,給定 n,m,求 [1, n] 以內 x 解的個數。

解可能很大,輸出取模 998244353。

輸入格式

其中 n 的給定方式是由 c 個不超過 t 的質數的乘積給出的,c 和 t 的範圍會在資料範圍中給出。

第一行一個 id 表示這個資料點的標號。

多組資料,其中第二行一個整數 T 表示資料組數。對於每一組資料:

第一行兩個整數 c 和 m。

第二行 c 個整數,這些整數都是質數,且兩兩不同,他們的乘積即為n。

由於你可以通過輸入求出 t,輸入不再給出。

輸出格式

對於每組資料輸出一行,表示解的個數。

樣例資料

input

0
1
2 3
2 3

output

6

資料規模與約定

其中所有資料點都滿足 1 ≤ c ≤ 50,1 ≤ t ≤ 104,1 ≤ m ≤ 109,1 ≤ T ≤10000。

時間限制:2.5s

空間限制:256MB

中國剩餘定理求方案數
暴力是對每個方程用快速冪枚舉出可能解最後乘起來,80分
優秀的做法是用積性函式優化掉合數的快速冪,AC

#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = j;i <= k;++i)
#define repp(i,j,k) for(int i = j;i >= k;--i) #define rept(i,x) for(int i = linkk[x];i;i = e[i].n) #define P pair<int,int> #define Pil pair<int,ll> #define Pli pair<ll,int> #define Pll pair<ll,ll> #define pb push_back #define pc putchar #define mp make_pair #define file(k) memset(k,0,sizeof(k))
#define ll long long const int p = 998244353; int t[60]; int num[60]; int ans; int c,m; int prime[11000] , tot; bool flag[10010]; int read() { int sum = 0;char c = getchar();bool flag = true; while(c < '0' || c > '9') {if(c == '-') flag = false;c = getchar();} while(c >= '0' && c <= '9') sum = sum * 10 + c - 48,c = getchar(); if(flag) return sum; else return -sum; } int Pow(int a,int x,int p) { int sum = 1; while(x) { if(x & 1) sum = 1ll * sum * a % p; a = 1ll * a * a % p; x >>= 1; } return sum; } int mi[10100]; void work(int m,int n,int x) { memset(flag,0,sizeof(flag));tot = 0; rep(i,2,n - 1) { if(!flag[i]) { prime[++tot] = i; mi[i] = Pow(i,m,n); } rep(j,1,tot) { if(prime[j] * i > n) break; flag[prime[j] * i] = true; mi[prime[j]*i] = mi[prime[j]] * mi[i] % n; if(i % prime[j] == 0) break; } num[x] += mi[i] == i; } } void print(int x) { if(x < 0) {putchar('-');x = -x;} if(x >= 10) { print(x / 10); } putchar('0' + x % 10); } void init() { c = read(),m = read();ans = 1; rep(i,1,c) t[i] = read(),num[i] = 2,work(m,t[i],i),ans = 1ll*ans*num[i]%p; print(ans);putchar('\n'); } int main() { freopen("division.in","r",stdin); freopen("division.out","w",stdout); int T = read();T = read(); while(T--) init(); return 0; }