前言
- 比賽連結。
最可惜的一點還是本來 T3 暴力能拿 \(20\),最佳化成 \(15\) 了,不然就 rk2 了,晚上可能又有泡麵吃了。
不過因為 T2、T4 兩道水題,剩下兩道不太可做(至少對於我是這樣的),這兩題不掛分的打的貌似都不錯。
T3 沒學過莫反輸麻了。
T1 黑暗型高松燈
本來應該是 T4,學長特意把 T1、T4 swap 了,不可做題,學長和我們說用處不大可以不用改,是什麼勢能函式之類的東西,聽都沒沒聽過。
T2 速度型高松燈
- 原題:P3216 [HNOI2011] 數學作業。
做過原題?賽時忘了做過當新題做的,賽後找原題才發現做過。
設 \(t\) 表示當前數字的位數,有 \(f_x = f_{x-1} \times 10^t + x\) ,位數一樣的矩陣快速冪,位數不同的兩個連線點特殊處理即可。
對於位數一樣的,有:
我這個做法不開 __int128 會炸。
點選檢視程式碼
#include<bits/stdc++.h>
#define ll __int128
#define endl '\n'
#define sort stable_sort
using namespace std;
const int N=1e5+10;
template<typename Tp> inline void read(Tp&x)
{
x=0;register bool z=true;
register char c=getchar();
for(;c<'0'||c>'9';c=getchar()) if(c=='-') z=0;
for(;'0'<=c&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
x=(z?x:~x+1);
}
template<typename Tp> inline void wt(Tp x)
{if(x>9)wt(x/10);putchar((x%10)+'0');}
template<typename Tp> inline void write(Tp x)
{if(x<0)putchar('-'),x=~x+1;wt(x);}
ll n,m,P,a[10][10],ans[10][10],c[10][10],last,ans1,ans2,anss;
ll qpow(ll a,ll b)
{
ll ans=1;
for(;b;b>>=1)
{
if(b&1) ans*=a;
a*=a;
}
return ans;
}
void qpow(ll b)
{
memset(ans,0,sizeof(ans));
for(int i=1;i<=3;i++) ans[i][i]=1;
for(;b;b>>=1)
{
if(b&1)
{
for(int i=1;i<=3;i++)
for(int j=1;j<=3;j++)
for(int k=1;k<=3;k++)
(c[i][j]+=(ans[k][j]*a[i][k])%P)%=P;
for(int i=1;i<=3;i++)
for(int j=1;j<=3;j++)
{
ans[i][j]=c[i][j];
c[i][j]=0;
}
}
for(int i=1;i<=3;i++)
for(int j=1;j<=3;j++)
for(int k=1;k<=3;k++)
(c[i][j]+=(a[i][k]*a[k][j])%P)%=P;
for(int i=1;i<=3;i++)
for(int j=1;j<=3;j++)
{
a[i][j]=c[i][j];
c[i][j]=0;
}
}
}
signed main()
{
read(n),read(P);
ll y=n;
while(y) {m++; y/=10;}
for(int i=1;i<=m;i++)
{
ll t=qpow(10,i);
a[1][1]=t,a[2][1]=1,a[3][1]=1;
a[1][2]=0,a[2][2]=1,a[3][2]=1;
a[1][3]=0,a[2][3]=0,a[3][3]=1;
ll x=t/10;
if(i!=m) qpow(t-x-2);
else
{
if(n>x) qpow(n-x-1);
else
{
anss=((last*t)%P+x)%P;
break;
}
}
ans2=((last*t)%P+x)%P;
ans1=((ans2*t)%P+x+1)%P;
anss=(((ans1*ans[1][1])%P+((x+1)*ans[2][1])%P)%P+1*ans[3][1])%P;
last=anss;
}
write(anss);
}
T3 力量型高松燈
-
原題:P6156 簡單題,加強版:P6222 「P6156 簡單題」加強版。
-
部分分 \(20pts\):\(O(n^2\log n)\) 暴力,預處理可到 \(O(n^2)\)。
-
正解:
大多數人能一眼看出莫反,到我沒學過,賽後找了篇部落格但沒認真學,就看了看到把題解看懂的地步,有時間再系統學。
就看到了一個 \((\sum\limits_{d|n}\mu(d))=[n=1]\) 做這題有用的,剩下的都是套路。
\[\begin{aligned} &\sum_{i=1}^n\sum_{j=1}^n(i+j)^k\mu^2(\gcd(i,j))\gcd(i,j)\\ =&\sum_{d=1}^n\mu^2(d)d\sum_{i=1}^n\sum_{j=1}^n(i+j)^k[\gcd(i,j)=d]\\ =&\sum_{d=1}^n\mu^2(d)d\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{n}{d}\rfloor}(d(i+j))^k[\gcd(i,j)=1]\\ =&\sum_{d=1}^n\mu^2(d)d^{k+1}\sum_{i=1}^{\lfloor\frac nd\rfloor}\sum_{j=1}^{\lfloor\frac nd\rfloor}(i+j)^k[\gcd(i,j)=1]\\ =&\sum_{d=1}^n\mu^2(d)d^{k+1}\sum_{i=1}^{\lfloor\frac nd\rfloor}\sum_{j=1}^{\lfloor\frac nd\rfloor}(i+j)^k\sum_{e|i,e|j}\mu(e)\\ =&\sum_{d=1}^n\mu^2(d)d^{k+1}\sum_{i=1}^{\lfloor\frac n{de}\rfloor}\sum_{j=1}^{\lfloor\frac n{de}\rfloor}(e(i+j))^k\sum_{e|i,e|j}\mu(e)\\ =&\sum_{e=1}^n\mu(e)e^k\sum_{d=1}^{\lfloor\frac ne\rfloor}\mu^2(d)d^{k+1}\sum_{i=1}^{\lfloor\frac n{de}\rfloor}\sum_{j=1}^{\lfloor\frac n{de}\rfloor}(i+j)^k\\ =&\sum_{T=1}^nS\left(\left\lfloor\frac nT\right\rfloor\right)T^k\sum_{d|T}\mu^2(d)\mu\left(\frac Td\right)d \end{aligned} \]其中 \(S(n)=\sum\limits_{i=1}^n\sum\limits_{j=1}^n(i+j)^k\)。
問題來到怎麼求 \(S(n)\) 和它後面那一坨。
先求後面那一坨,設 \(f(n)=\sum\limits_{d|T}\mu^2(d)\mu\left(\frac Td\right)d\),因為其內部均為積性函式,故 \(f(n)\) 也是積性函式,對於質數 \(p\),其次方為 \(c\) 。
- 若 \(c=1\),滿足積性。
- 若 \(c=2\),\(f(p^2)=\mu^2(p^2)\mu(1)p^2+\mu^2(p)\mu(p)p+\mu^2(1)\mu(p^2)\times 1=-p\)。】
- 若 \(c>2\),任意組合均能使 \(\mu(d),\mu(\frac Td)\) 中的一個為 \(0\),故結果一定為 \(0\)。
線性篩的時候直接處理即可。
來看 \(S(n)\),設 \(F(n)=\sum\limits_{i=1}^ni^k\),\(G(n)=\sum\limits_{i=1}^nF(i)\),那麼有 \(S(n)=G(2n)-2G(n)\),證明比較顯然,可以手摸一下,也可以數學歸納。
由於 \(i^k\) 也是積性函式,篩的時候直接處理即可。
最後數論分塊處理答案即可。
點選檢視程式碼
#include<bits/stdc++.h> #define ll long long #define endl '\n' #define sort stable_sort using namespace std; const int N=1e7+10,P=998244353; template<typename Tp> inline void read(Tp&x) { x=0;register bool z=true; register char c=getchar(); for(;c<'0'||c>'9';c=getchar()) if(c=='-') z=0; for(;'0'<=c&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48); x=(z?x:~x+1); } template<typename Tp> inline void wt(Tp x) {if(x>9)wt(x/10);putchar((x%10)+'0');} template<typename Tp> inline void write(Tp x) {if(x<0)putchar('-'),x=~x+1;wt(x);} ll n,k,tot,cnt,ans,prime[N],f[N],g[N]; bool vis[N]; ll qpow(ll a,ll b) { ll ans=1; for(;b;b>>=1) { if(b&1) (ans*=a)%=P; (a*=a)%=P; } return ans; } void sieve() { f[1]=g[1]=1; for(int i=2;i<=2*n;i++) { if(!vis[i]) { prime[++tot]=i; f[i]=i-1; g[i]=qpow(i,k); } for(int j=1;j<=tot&&i*prime[j]<=2*n;j++) { vis[i*prime[j]]=1; g[i*prime[j]]=g[i]*g[prime[j]]%P; if(i%prime[j]==0) { if((i/prime[j])%prime[j]!=0) f[i*prime[j]]=(P-prime[j])*f[i/prime[j]]%P; break; } f[i*prime[j]]=f[i]*f[prime[j]]%P; } } for(int i=2;i<=2*n;i++) { f[i]=(f[i-1]+f[i]*g[i]%P)%P; g[i]=(g[i-1]+g[i])%P; } for(int i=2;i<=2*n;i++) g[i]=(g[i-1]+g[i])%P; } ll s(ll x) { return (g[x<<1]-2*g[x]%P+P)%P; } signed main() { read(n),read(k); sieve(); for(ll l=1,r=0;l<=n;l=r+1) { r=n/(n/l); (ans+=s(n/l)*((f[r]-f[l-1]+P)%P)%P)%=P; } write(ans); }
T4 高松燈
看題名就知道簽到題,要麼取自己要麼第一位取次大值後面全取 \(9\),但我賽時想都沒想搞了個數位 DP 上去。
總結
沒學過的知識點還是太多,這次只掛了 \(5pts\) 而且打的不是很唐,所以好像沒啥心得,好多題逆推退不出來想想正推,反過來也是,T2 倒推半天出不來正推直接過了。
附錄
雖然今天可惜沒拿到 rk2,但昨天賽後搶到學長最優解搞到一桶泡麵,就當昨天那個是今天拿的吧。