CSP 后多校十一
NOIP2018
感觉不是很难,一开始想的是二分最多能选多少个物品,然后一元二次函数直接 \(O(1)\) 出结果.
但是被卡精度了,其实只用二分每个物品最多花多少钱,画两个一元二次函数就行了.
因为两个物品的花费越接近越优,于是就完了.
CSP 2019
多项式不会.
CSP 2020
考场上想到可能是数位\(dp\),也想到可能是大点和小店是要分开做的,但是没想到要把两个结合起来..
发现 \(n>12\) 的情况和 \(n\le 12\) 的情况可以分开做,原因是 \(1+\dfrac{n^3}{9}+C(\dfrac{n^3}{9},2)\ge n^4\).
所以小点数位 \(dp\),直接暴力 \(O(n^2)\) 走,大点直接枚举就可以了.
C_code
#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);
}
NOIP 2021
原根不会.