Mys_C_K的数论方程好题

题目大意:
给定两个长为n的数列F和B,求长为n的数列x,使得 i [1,n],nj=1F(gcd(i,j)) xj=Bi ∀ i ∈   [ 1 , n ] , ∑ j = 1 n F ( g c d ( i , j ) )   x j = B i 在模998244353意义下成立。 n105 n ≤ 10 5

题解:
考虑令 F(n)=d|nf(d) F ( n ) = ∑ d | n f ( d ) ,那么 f(n)=F(n)d|n,dnf(d) f ( n ) = F ( n ) − ∑ d | n , d ≠ n f ( d ) ,因此可以再 O(nlgn) O ( n l g n ) 时间内通过 F(n) F ( n ) 求出 f(n) f ( n )
将题目中的F改写成f,有:
i [1,n],nj=1d|i,d|jf(d) xj=Bi ∀ i ∈   [ 1 , n ] , ∑ j = 1 n ∑ d | i , d | j f ( d )   x j = B i
i [1,n],d|if(d)nd|j xj=Bi ∀ i ∈   [ 1 , n ] , ∑ d | i f ( d ) ∑ d | j n   x j = B i
x(n)=n|dxd x ( n ) = ∑ n | d x d ,那么 xn=x(n)n|d,ndxd x n = x ( n ) − ∑ n | d , n ≠ d x d ,因此知道x(n)后可以 O(nlgn) O ( n l g n ) 时间内求出 xn x n
i [1,n],d|if(d)x(d)=Bi ∀ i ∈   [ 1 , n ] , ∑ d | i f ( d ) x ( d ) = B i
i [1,n],d|ih(d)=b(i) ∀ i ∈   [ 1 , n ] , ∑ d | i h ( d ) = b ( i )
根据上文结论,知道 b(n) b ( n ) 之后可以 O(nlgn) O ( n l g n ) 时间内求出 h(n) h ( n ) ,进而求出 x(n) x ( n ) ,进而求出 xn x n
具体来说,以已知 F F f,代码大致如下:

for(int i=1;i<=n;i++) f[i]=F[i];
for(int i=1;i<=n;i++)
    for(int j=i<<1;j<=n;j++)
        f[j]-=f[i];

另一个同理。
代码:

// luogu-judger-enable-o2
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define N 100010
#define mod 998244353
#define lint long long
#define gc getchar()
using namespace std;
int f[N],x[N],fi[N];
inline int inn()
{
    int x,ch;while((ch=gc)<'0'||ch>'9');
    x=ch^'0';while((ch=gc)>='0'&&ch<='9')
        x=(x<<1)+(x<<3)+(ch^'0');return x;
}
inline int mol(int x) { return x%=mod,(x<0?x+=mod:x); }
inline int fast_pow(int x,int k=mod-2,int ans=1)
{   for(;k;k>>=1,x=(lint)x*x%mod) (k&1)?ans=(lint)ans*x%mod:0;return ans;   }
inline int getf(int *f,int n)
{
    for(int i=1;i<=n;i++)
        for(int j=i<<1;j<=n;j+=i) f[j]=mol(f[j]-f[i]);
    return 0;
}
inline int getg(int *g,int n)
{
    for(int i=n;i>=1;i--)
        for(int j=i<<1;j<=n;j+=i) g[i]=mol(g[i]-g[j]);
    return 0;
}
int main()
{
    int n=inn();
    for(int i=1;i<=n;i++) f[i]=inn();getf(f,n);
    for(int i=1;i<=n;i++) fi[i]=fast_pow(f[i]);
    for(int i=1;i<=n;i++) x[i]=inn();getf(x,n);
    for(int i=1;i<=n;i++) x[i]=(lint)x[i]*fi[i]%mod;
    getg(x,n);for(int i=1;i<=n;i++) printf("%d ",x[i]);
    return !printf("\n");
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值