您的位置:首页 > 其它

VIJOS 1278 My Story Your Song-雨天

2016-06-27 23:25 429 查看

题意简述

在前n个正整数中选取m个数ai,使得1/ai之和为X/Y

分析

HNOI的一道题 《彩票》

直接n选m的搜索,加上可行性剪枝(继续选总和一定小于或大于X/Y)似乎就可以过了

但是时间效率不太理想

尝试了2个优化:

1预处理1/i 减少实数运算

2先dp一下前n个数选m个hash值为p是否可行

在搜索时发现当前hash值不可行就直接剪枝

这2个优化效果都比较显著

优化2更是将效率提升为原来的10倍

代码

#include<cstdio>
#include<cmath>
#define fo(i,a,b) for(int i=a;i<=b;i++)
int n,m,x,y,ans;
typedef double ld;
const int p=5003;
const long double eps=(ld)1e-10 ;//1e-9  (lf)
ld f,d[100],g[100];
int a[1000],ni[300],hf;
bool h[70][70][p+10];
double lfabs(ld a){
if (a<0)
return -a;
return a;
}
int pow(int a,int n){
int ans=1;
while (n){
if (n&1)
ans=ans*a%p;
a=a*a%p;
n>>=1;
}
return ans;
}
void dfs(int la,int now,ld s,int u){
if (u>=p)
u-=p;
if (!h[la+1][m-now][(hf-u+p)%p])
return;
if (now==m){
if (lfabs(s-f)<eps){//abs  fabs
ans++;
/*printf("%d:\n",ans);
fo(i,1,m)
printf("%d ",a[i]);
putchar('\n');*/
}
return;
}
/*if ((s+((ld)(m-now+1)/(la+1)))<f)
return;
if ((s+((ld)(m-now+1)/n))>f)
return;*/
if (s+g[la+m-now]-g[la]<f-eps)//la+m   eps
return;
if (s+g
-g[n-m+now]>f+eps)
return;
fo (i,la+1,n){//n-m+now
//a[now]=i;
dfs(i,now+1,s+d[i],u+ni[i]);
}
}
int main(){
scanf("%d%d%d%d",&m,&n,&x,&y);
fo(i,1,n)
ni[i]=pow(i,p-2);
//printf("%d\n",ni[5]);
h[n+1][0][0]=1;
for(int i=n;i>=1;i--){
h[i][0][0]=1;
fo(k,0,p-1){
int t=k-ni[i];
if (t<0)
t+=p;
fo(j,1,m){
h[i][j][k]=h[i+1][j][k]||h[i+1][j-1][t];
}
}
}
fo(i,1,n)
d[i]=(ld)1/i;
fo(i,1,n)
g[i]=g[i-1]+d[i];
f=(ld)x/y;hf=x*ni[y]%p;
dfs(0,0,0,0);
printf("%d\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  vijos hash 搜索