【JZOJ7217】数学
by AmanoKumiko
Description
定义一个整数\(a_1...a_n(0≤a1≤9)\)是好的,当且仅当至少存在一个\(i(1≤i≤n-2)\)满足\(a_i≤a_{i+1}≤a_{i+2}\)
不会数学的\(wls\)想让你求出最小的\(n\),使得\(1...n\)这\(n\)个整数中好的整数的个数的比例大于等于给定的比例\(p\)
Input
一个五位小数\(p\)
Output
一个数\(n\)
Sample Input
0.20000
Sample Output
1464
Data Constraint
对于100%的数据,\(0<p<1\)
Solution
先考虑知道\(n\)的情况下怎么计算个数,这是一个简单的数位dp
然后这种题有通用trick
设\(B\)为当前的\(n\),\(A\)为\(B\)中好的整数的个数
那么我们找到一个最小的整数\(C\)
使得\(\frac{A+C}{B+C}≥p\)?
令\(B=B+C\),重新计算\(A\)
若\(\frac{A}{B}≥p\),此时的\(B\)就是答案
然而这个出题人很无聊,硬要上高精
为了避免高精除,我们给不等式移项,两边都乘上\(10^5\)
这样变成高精除低精,好算一些
Code
#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
using namespace std;
#define F(i,a,b) for(int i=a;i<=b;i++)
#define Fd(i,a,b) for(int i=a;i>=b;i--)
#define mo 100000000
#define LL long long
#define Ld long double
#define N 90
Ld p;
int nt,num[N],pi;
bool vis[N][11][11][2][2][2];
struct node{int l;LL v[20];}A,B,C,P,E,a,b,c,f[N][11][11][2][2][2];
node operator+(const node&le,const node&ri){
B=le;C=ri;
memset(A.v,0,sizeof(A.v));
A.l=max(B.l,C.l);
F(i,1,A.l){
A.v[i]+=B.v[i]+C.v[i];
A.v[i+1]+=A.v[i]/mo;
A.v[i]%=mo;
}
A.l=(A.v[A.l+1]?A.l+1:A.l);
return A;
}
node operator-(const node &le,const node &ri){
B=le;C=ri;
A.l=B.l;
memset(A.v,0,sizeof(A.v));
F(i,1,A.l){
if(B.v[i]<C.v[i])B.v[i+1]--,B.v[i]+=mo;
A.v[i]=B.v[i]-C.v[i];
}
while(!A.v[A.l]&&A.l)A.l--;
return A;
}
node operator*(const node&le,const node&ri){
B=le;C=ri;
memset(A.v,0,sizeof(A.v));
F(j,1,C.l) F(i,1,B.l){
A.v[j+i-1]+=C.v[j]*B.v[i];
A.v[j+i]+=A.v[j+i-1]/mo;
A.v[j+i-1]%=mo;
}
A.l=(A.v[B.l+C.l]?B.l+C.l:B.l+C.l-1);
while(!A.v[A.l]&&A.l)A.l--;
return A;
}
node operator/(const node&le,const LL&ri){
B=le;
A.l=B.l;
memset(A.v,0,sizeof(A.v));
LL rest=0;
Fd(i,B.l,1){
(rest*=mo)+=B.v[i];
if(rest>=ri)A.v[i]=rest/ri,rest=rest%ri;
}
while(!A.v[A.l]&&A.l)A.l--;
return A;
}
bool operator>=(const node&le,const node&ri){
if(le.l>ri.l)return 1;
if(le.l<ri.l)return 0;
Fd(i,le.l,1)if(le.v[i]!=ri.v[i])return le.v[i]>=ri.v[i];
return 1;
}
node dfs(int x,int l1,int l2,bool flag,bool lim,bool zero){
node res;res.l=0;
memset(res.v,0,sizeof(res.v));
if(!x){if(flag)res.v[res.l=1]=1;return res;}
if(vis[x][l1][l2][flag][lim][zero])return f[x][l1][l2][flag][lim][zero];
int up=lim?9:num[x];
F(j,0,up){
bool fn=flag|(l1<9&&l2<9&&l1<l2&&l2<j);
bool ln=lim|(j<num[x]);
bool zn=zero&&(j==0);
res=res+dfs(x-1,zn?10:l2,zn?10:j,zn?0:fn,zn?1:ln,zn);
}
vis[x][l1][l2][flag][lim][zero]=1;
return (f[x][l1][l2][flag][lim][zero]=res);
}
int main(){
scanf("%Lf",&p);
pi=p*100000;
E.v[E.l=1]=100000;
P.v[P.l=1]=pi;
b.v[b.l=1]=1;
while(1){
c=(P*b-a*E)/(100000-pi);
if(c.l==0)c.v[c.l=1]=1;
b=b+c;
memset(vis,0,sizeof(vis));
nt=0;
F(i,1,b.l){
int cnt=0,x=b.v[i];
while(x)cnt++,num[++nt]=x%10,x/=10;
if(i!=b.l)F(j,1,8-cnt)num[++nt]=0;
}
a=dfs(nt,10,10,0,0,1);
if(a*E>=P*b){
Fd(i,b.l,1){
int cnt=0,x=b.v[i];
while(x)cnt++,x/=10;
if(i!=b.l)F(j,1,8-cnt)printf("0");
printf("%d",b.v[i]);
}
break;
}
}
return 0;
}