感觉不是很难,一开始想的是二分最多能选多少个物品,然后一元二次函数直接 \(O(1)\) 出结果.
但是被卡精度了,其实只用二分每个物品最多花多少钱,画两个一元二次函数就行了.
因为两个物品的花费越接近越优,于是就完了.
多项式不会.
考场上想到可能是数位\(dp\),也想到可能是大点和小店是要分开做的,但是没想到要把两个结合起来..
发现 \(n>12\) 的情况和 \(n\le 12\) 的情况可以分开做,原因是 \(1+\dfrac{n^3}{9}+C(\dfrac{n^3}{9},2)\ge n^4\).
所以小点数位 \(dp\),直接暴力 \(O(n^2)\) 走,大点直接枚举就可以了.
#include<bits/stdc++.h> using namespace std; namespace BSS{ #define int long long #define lf long double #define pb push_back #define mp make_pair #define lb lower_bound #define ub upper_bound #define lbt(x) ((x)&(-(x))) #define Fill(x,y) memset(x,y,sizeof(x)) #define Copy(x,y) memcpy(x,y,sizeof(x)) #define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout) auto read=[](int w=0,bool cit=0,char ch=getchar())->int{ for(;!isdigit(ch);ch=getchar()) cit=(ch=='-'); for(;isdigit(ch);ch=getchar()) w=(w<<3)+(w<<1)+(ch^48); return cit?(-w):w; }; } using namespace BSS; const int N=2e3+21; int m,n,mod,ans,os,osm,bs; int ret[10]={0,1,161,6966,59899897}; int pos[N]; int dp[N][N]; auto ksm=[](int a,int b,int c,int w=1)->int{ for(a%=c;b;b>>=1,a=a*a%c) if(b&1) w=w*a%c; return w%c; }; auto PreWork=[]()->void{ dp[0][0]=1; for(int i=0;i<=1800;i++){ for(int j=1;j<=1800;j++){ for(int k=0,lmk=min(i,9ll);k<=lmk;k++) dp[i][j]=dp[i][j]+dp[i-k][j-1]; } } }; auto SpWork=[](int x)->void{ int l=1,r=1800,mid,res,smx=pow(x,3),por=smx*x,now=0; ans=0; while(l<=r){ mid=(l+r)>>1; if(dp[smx][mid]>=por or dp[smx][mid]<0) r=mid-1,res=mid; else l=mid+1; } for(int i=1;i<res;i++) now+=dp[smx][i]-dp[smx][i-1]; for(int i=1,lft=smx;i<=res;i++){ for(int j=(i==1),flag=1;j<=9 and flag;j++){ if(now+dp[lft-j][res-i]>=por) flag=0,pos[i]=j,lft-=j; else now+=dp[lft-j][res-i]; } } for(int i=1;i<=res;i++) ans=(ans+ksm(10,res-i,mod)*pos[i]%mod)%mod; printf("%lld ",ans); return void(); }; auto Work=[](int x)->void{ int smx=pow(x,3),por=smx*x,now=smx%9+2,cnt=smx/9; ans=now; if(ans>9) ans=(ans%9*10+9)%mod; for(int i=1,lmi=cnt/os;i<=lmi;i++) ans=(ans*osm+bs)%mod; for(int i=1,lmi=cnt%os;i<=lmi;i++) ans=(ans*10ll+9)%mod; por-=1+cnt,cnt+=(now>9); for(int i=1;i<=cnt;i++){ if(por<=cnt-i+1){ ans=(ans-ksm(10,cnt-i,mod)-ksm(10,cnt-i+1-por,mod)+mod*2)%mod; return printf("%lld ",ans),void(); } por-=(cnt-i+1); } }; signed main(){ File(number); n=read(),mod=read(); PreWork(); os=40000,osm=ksm(10,os,mod); for(int i=1;i<=os;i++) bs=(bs*10+9)%mod; for(int i=1,lmi=min(n,12ll);i<=lmi;i++) SpWork(i); for(int i=13;i<=n;i++) Work(i); exit(0); }
原根不会.