【JZOJ7217】数学

【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;
}
posted @ 2021-08-13 19:57  冰雾  阅读(26)  评论(0编辑  收藏  举报