GDKOI2023 D1T1
前言
考場上沒想出來,收到來自題目標題的嘲諷
題目大意
求 ∑ i = 1 n i ! i k ( m o d 998244353 ) \sum\limits_{i=1}^n\frac{i!}{i^k}\left(\mod 998244353\right) i=1∑n?iki!?(mod998244353) ,其中 n ( 1 ≤ 2 × 1 0 7 ) , k ( 1 ≤ k ≤ 2 × 1 0 7 ) n(1\le 2\times10^7),k(1\le k\le 2\times 10^7) n(1≤2×107),k(1≤k≤2×107) 為輸入給出。
解題思路
對于暴力思路,直接爆算即可,時間復雜度為 O ( ( log ? 2 k + log ? 2 998244353 ) × n ) O\left(\left(\log_2k+\log_2998244353\right)\times n\right) O((log2?k+log2?998244353)×n) 大常數 O ( n ) O(n) O(n) 但常數太大,過不去。
考慮優化——預處理。我們可以預處理出 1 ~ n 1\sim n 1~n 范圍內所有數的 k k k 次方在 m o d 998244353 \mod 998244353 mod998244353 意義下的逆元,進一步思考,由于 a = b × c a=b\times c a=b×c 則 a ? 1 = b ? 1 × c ? 1 a^{-1}=b^{-1}\times c^{-1} a?1=b?1×c?1,可以使用歐拉篩進行處理。具體地說,就算對于每個質數,可以直接計算其 k k k 次方的逆元:
而對于合數,則將其拆成兩個數相乘,借此得到其逆元:
for(int i=2;i<=n;i++){if(!a[i]){ans[++tot]=i;a[i]=_pow(_pow(i,m),Mod-2);}for(int j=1;j<=tot&&ans[j]*i<=n;j++){a[ans[j]*i]=a[ans[j]]*a[i]%Mod;//此處if(i%ans[j]==0)break;}}代碼實現
#include<bits/stdc++.h> using namespace std; const long long Mod=998244353; long long n,m,tot,a[20000010],output,now=1; int ans[5000010]; long long _pow(long long d,long long z) {long long ans=1;while(z){if(z&1)ans=ans*d%Mod;d=d*d%Mod;z>>=1;}return ans; } int main() {ios::sync_with_stdio(false);cin.tie(0);freopen("math.in","r",stdin);freopen("math.out","w",stdout);cin>>n>>m;a[1]=1;for(int i=2;i<=n;i++){if(!a[i]){ans[++tot]=i;a[i]=_pow(_pow(i,m),Mod-2);}for(int j=1;j<=tot&&ans[j]*i<=n;j++){a[ans[j]*i]=a[ans[j]]*a[i]%Mod;if(i%ans[j]==0)break;}}for(int i=1;i<=n;i++){ // cout<<a[i]<<"\n";now=now*i%Mod;output=(output+now*a[i])%Mod;}cout<<output;return 0; }總結
以上是生活随笔為你收集整理的GDKOI2023 D1T1的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java后台关联微信公众号开发
- 下一篇: Siki_Unity_3-16_3D数学