【学习笔记】NOIP爆零赛6

说实话是不想补题的。因为每一道题都贼难写,题解又通篇写着显然,然后自己天天搞竞赛又把注意力搞差了,调一道题又调半天,考试的题又难的要死 不会正解 ,部分分又写挂了 可能心态崩了就是从那场 t 1 t1 t1签到题考高精度数位 d p dp dp容斥开始的吧

young

没错,又是一来第一道题就把你心态搞崩了。

这一看就是一个非常暴力非常玄学的 d p dp dp那么问题来了,机房里只有一个人过了,这是为什么呢

现在来想这个题还是觉得非常抽象。反正确实没啥好办法,就照着出题人的做法学吧。

反正考场上也就只能 30 p t s 30pts 30pts跑路了。

simple

这场唯一能做的题。不过还是需要猜到一个小结论才能做出来。

首先看这道题,和最小表示法很像,但是又不完全是,因为后面那些位填的是 0 0 0

如果这个串的循环节长度 < n <n <n的话,那么这个串肯定是不合法的,因为最小表示不唯一,而又要求严格大于。然后最小表示唯一了,这里又可以猜这些轮换中合法的恰好对答案的贡献是 1 1 1,于是可以得到:

f ( i ) = ∑ j ∣ i 1 0 j μ ( i / j ) i f(i)=\frac{\sum_{j|i}10^j\mu(i/j)}{i} f(i)=iji10jμ(i/j)

直接暴力算复杂度 O ( n ln ⁡ n ) O(n\ln n) O(nlnn)。说实话我考场上想到这里的时候脑子都是混乱的,完全想不清楚了 原因如上 ,结果数组开爆直接gg。

说到底还是被 t 1 t1 t1坑了。本来以为 t 1 t1 t1可以切掉的,结果谁知道越想越复杂,越想越觉得不对,直接整出心理阴影了。当然还有一个原因,我对数论函数不是很熟悉,所以考场上完全没往这方面想,就想硬刚数数题

唉,感觉模拟赛的出题人出题风格和atcoder完全不同,做着很难受啊

注意到 1 0 j 10^j 10j不是积性函数,因此这里要把它提出来计算:

∑ 1 0 j × j × ∑ i ≤ ⌊ n j ⌋ ( i × μ ( i ) ) \sum 10^j\times j\times \sum_{i\le \lfloor\frac{n}{j}\rfloor}(i\times \mu(i)) 10j×j×ijn(i×μ(i))

可以直接计算,复杂度 O ( n ) O(n) O(n),有 60 p t s 60pts 60pts

可以用整除分块+杜教筛优化,套两个板子即可。说实话考这种优化挺无聊的,但是出题人要考又有什么办法呢,我还是滚回去复习一下模板吧

接下来是速成,建议不看

对于数论函数 f f f,要求我们计算 S ( n ) = ∑ i = 1 n f ( i ) S(n)=\sum_{i=1}^n f(i) S(n)=i=1nf(i)

对于任意数论函数 g g g必满足 ∑ i = 1 n ( f ∗ g ) ( i ) = ∑ i = 1 n g ( i ) S ( ⌊ n i ⌋ ) \sum_{i=1}^n(f*g)(i)=\sum_{i=1}^ng(i)S(\lfloor\frac{n}{i}\rfloor) i=1n(fg)(i)=i=1ng(i)S(⌊in⌋)

那么可以得到递推式 S ( n ) = ∑ i = 1 n ( f ∗ g ) ( i ) − ∑ i = 2 n g ( i ) S ( ⌊ n i ⌋ ) S(n)=\sum_{i=1}^n(f*g)(i)-\sum_{i=2}^ng(i)S(\lfloor\frac{n}{i}\rfloor) S(n)=i=1n(fg)(i)i=2ng(i)S(⌊in⌋)

只要预处理前 n 2 3 n^{\frac{2}{3}} n32个值即可,其他可以递归计算。

想必聪明的你应该已经知道该怎么做了吧

#include<bits/stdc++.h> #define ll long long using namespace std; const int mod=258280327; const int N=1e7+5; int cnt; int prime[N/10]; ll mu[N],pw[N]; bool vs[N]; ll n,n2,res,inv9,inv2=(mod+1)/2; ll fpow(ll x,ll y=mod-2){ ll z(1); for(;y;y>>=1){ if(y&1)z=z*x%mod; x=x*x%mod; }return z; } void init(int n){ mu[1]=1;pw[0]=1;pw[1]=10; for(int i=2;i<=n;i++){ pw[i]=pw[i-1]*10%mod; if(!vs[i]){ prime[++cnt]=i,mu[i]=-1; } for(int j=1;j<=cnt&&prime[j]<=n/i;j++){ vs[i*prime[j]]=1; if(i%prime[j]==0)break; mu[i*prime[j]]=-mu[i]; } }for(int i=1;i<=n;i++){ mu[i]=(mu[i-1]+mu[i]*i)%mod; } } map<ll,ll>dp; ll calc3(ll l){ return l*(l+1)%mod*inv2%mod; } ll S(ll n){ if(n<=n2)return mu[n]; if(dp.find(n)!=dp.end())return dp[n]; ll res=1; for(ll l=2,r;l<=n;l=r+1){ r=n/(n/l); res=(res-(calc3(r)-calc3(l-1))*S(n/l))%mod; }return dp[n]=res; } ll calc2(ll l){ return (fpow(10,l+1)-10)*inv9%mod; } ll calc(ll l){ return (fpow(10,l+1)*(l+1)-calc2(l+1))%mod*inv9%mod; } signed main(){ ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); cin>>n,n2=1e6,init(n2),inv9=fpow(9,mod-2); for(ll l=1,r;l<=n;l=r+1){ r=n/(n/l); res=(res+(calc(r)-calc(l-1))*S(n/l))%mod; }cout<<(res+mod)%mod; }

naive

出题人很友好。写出最无脑的 d p dp dp再找一下规律就有 50 p t s 50pts 50pts。真是谢谢出题人了。

首先还是假设第 0 0 0层存在,并且这一层的状态为 0 0 0,每次相当于猜一个楼层是 0 0 0还是 1 1 1,最后要还原整个状态,设 f i , j f_{i,j} fi,j表示楼层高度为 i i i,有 j j j个记者时的最小次数,根据定义有 f i , j = min ⁡ 1 ≤ k ≤ i max ⁡ ( f i − k , j , f k − 1 , j − 1 ) + 1 f_{i,j}=\min_{1\le k\le i}\max(f_{i-k,j},f_{k-1,j-1})+1 fi,j=min1kimax(fik,j,fk1,j1)+1

当然这样肯定是找不出来什么规律的,只能尝试一下其他的 d p dp dp方式。

g i , j g_{i,j} gi,j表示次数为 i i i,有 j j j个记者时,能得到的楼层最高高度。

还是考虑一次操作,如果返回的结果是 1 1 1的话,那么能确定 g i − 1 , j − 1 g_{i-1,j-1} gi1,j1的高度;如果返回的结果是 0 0 0的话,那么能确定 g i − 1 , j + 1 g_{i-1,j}+1 gi1,j+1的高度。那么 g i , j = g i − 1 , j − 1 + g i − 1 , j + 1 g_{i,j}=g_{i-1,j-1}+g_{i-1,j}+1 gi,j=gi1,j1+gi1,j+1

神谕告诉我们 g i , j = ∑ k = 1 j ( i k ) g_{i,j}=\sum_{k=1}^j\binom{i}{k} gi,j=k=1j(ki)。据说归纳法可证 但是我关心的是这是怎么看出来的啊233 可以自行打表验证。

这结论太小,以至于我看不见

因此直接二分就好啦。

#include<bits/stdc++.h> #define ll long long #define inf 0x3f3f3f3f #define db double using namespace std; int T,K; ll n; int check(ll mid){ db res=1,sum=0; for(int i=1;i<=K;i++){ res=res*(mid-i+1)/i; if((sum+=res)>=n)return 1; }return 0; } int main(){ ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); cin>>T; while(T--){ cin>>n>>K; if(K==1){ cout<<n<<"\n"; continue; } ll l=1,r=1e18,res=0; while(l<=r){ ll mid=l+r>>1; if(check(mid))res=mid,r=mid-1; else l=mid+1; }cout<<res<<"\n"; } }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530026.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(26)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示