前言
- 比赛链接。
最可惜的一点还是本来 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,但昨天赛后抢到学长最优解搞到一桶泡面,就当昨天那个是今天拿的吧。