1225: [HNOI2001] 求正整数

来源:互联网 发布:阿拉斯加捕鲸叉淘宝 编辑:程序博客网 时间:2024/06/07 15:51

数学蒟蒻来补数学了。

结果遇到了DP题,科学何在啊。。。。。

这题嘛,运用传说中的求约数个数的公式,我们可以发现DP方程

f[i][j]=min{f[k][j-1]*p[j]^(i/k-1),k|i}

于是就可以欢快地DP了。

但是。。。。。。。

但是。。。。。。

难道我要高精度DP吗?

显然不能

于是取个对数,DP的过程中把决策记录下来。

最后再计算。

精度什么的,咳咳,应该还好。

比较坑爹的是要先预处理下log[p[j]],因为我发现如果每次都算一次这个的话会超时。。。

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>using namespace std;int p[10000],tot;bool is[10000],vis[50005][20];double f[50000][20];void sieve(){for(int i=2;i<=10000;i++){if(!is[i])p[++tot]=i;for(int j=1;j<=tot&&p[j]*i<=10000;j++){is[p[j]*i]=true;if(i%p[j]==0)break;}}}struct bigint{int a[10000],len;bigint(){memset(a,0,sizeof(a));len=0;}bigint(int n){memset(a,0,sizeof(a));len=0;while(n){a[++len]=n%10;n/=10;}}void print(){for(int i=len;i>=1;i--)printf("%d",a[i]);printf("\n");}};bool operator<(bigint x,bigint y){if(x.len!=y.len)return x.len<y.len;for(int i=x.len;i>=1;i--)if(x.a[i]!=y.a[i])return x.a[i]<y.a[i];return false;}bigint operator+(bigint x,bigint y){bigint ans;for(int i=1;i<=x.len||i<=y.len;i++){ans.a[i]=x.a[i]+y.a[i];ans.a[i+1]=ans.a[i]/10;ans.a[i]%=10;}ans.len=max(x.len,y.len);if(ans.a[ans.len+1])ans.len++;return ans;}bigint operator*(bigint x,bigint y){bigint ans;int r;for(int i=1;i<=x.len;i++){r=0;for(int j=1;j<=y.len;j++){ans.a[i+j-1]+=x.a[i]*y.a[j]+r;r=ans.a[i+j-1]/10;ans.a[i+j-1]%=10;}ans.a[i+y.len]=r;}ans.len=x.len+y.len;while(!ans.a[ans.len]&&ans.len>0)ans.len--;return ans;}bigint operator^(bigint a,int k){bigint ret=bigint(1);while(k){if(k&1)ret=ret*a;a=a*a;k>>=1;}return ret;}int process[50005][20];bigint ans;void calc(int n,int j){if(!n||!j)return;int ti=process[n][j];ans=ans*(bigint(p[j])^(ti-1));calc(n/ti,j-1);}double logp[100];int main(){sieve();int n;scanf("%d",&n);f[1][0]=0;vis[1][0]=true;for(int i=1;i<=16;i++)logp[p[i]]=log(p[i]);for(int j=1;j<=16;j++)for(int k=1;k<=n;k++)for(int ti=1;ti*k<=n;ti++){if(!vis[k][j-1])continue;//long double tmp=f[k][j-1]*(bigint(p[j])^(ti-1));double tmp=f[k][j-1]+(ti-1)*logp[p[j]];if(!vis[ti*k][j]||tmp<f[ti*k][j]){vis[ti*k][j]=true;f[ti*k][j]=tmp;process[ti*k][j]=ti;}}double tmp;int pos;bool flag=true;for(int i=1;i<=16;i++)if(vis[n][i]){if(flag||f[n][i]<tmp){tmp=f[n][i];flag=false;pos=i;}}ans=bigint(1);calc(n,pos);ans.print();return 0;}


0 0
原创粉丝点击