九校联考DAY2T2(中国剩余定理,积性筛)

题目描述

整除符号为 |,d|n 在计算机语言中可被描述为 n%d == 0。

现有一算式 n| xm x m - 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 10 4 ,1 ≤ m ≤ 109 10 9 ,1 ≤ T ≤10000。

时间限制: 2.5s 2.5 s

空间限制: 256MB 256 MB


中国剩余定理求方案数
暴力是对每个方程用快速幂枚举出可能解最后乘起来,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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值