Loading

题解:P2236 [HNOI2002] 彩票

首先写个暴搜(这个应该都会吧),枚举出每种选择,然后选择完判断是否满足条件,满足就把答案数加一。

#include<bits/stdc++.h>
using namespace std;
int n,m,x,y,ans;
int a[1005];
double cal;
bool check(){
    double sum = 0;
    for(int i = 1;i <= n;++i){
        sum += 1.0 / a[i];
    }
    return abs(sum - cal) <= 1e-12;
}
void dfs(int k){//第k个数字
    if(k == n + 1){//找到了一种答案
        if(check())ans++;
        return ;
    }
    for(int i = a[k - 1] + 1;i <= m;++i){//从上一个数开始,一直枚举到m
        a[k] = i;
        dfs(k + 1);
    }
}
int main(){
    cin >> n >> m >> x >> y;
    cal = x * 1.0 / y;
    dfs(1);
    cout << ans << endl;
    return 0;
}

遗憾地拿了 10 pts。
考虑继续剪枝优化。

剪枝 1

如果和 \(>X/Y\),不用往下搜。

剪枝 2

如果剩下的数字都选择最大的,和依然小于 \(\frac{X}{Y}\)now+1.0/dep *(n-cnt)<X/Y ,剪枝。

剪枝 3

如果剩下的数字都选择最小的,和依然大于 \(\frac{X}{Y}\),剪枝。

剪枝 4

给出两种方案:
A:从 \(1\) 开始决策。
B:从 \(M\) 开始决策。
很明显方案 A 更快。

剪枝 5

注意到 \(M\) 的最大值只有 \(50\),想到从这里优化。发现 \(Y\) 最大只有 \(25\),因此选到的自然数,分母不能为大于 \(25\) 的质数!
因此可以先预处理出大于 \(25\) 的质数。
代码就很简单了:

#include<bits/stdc++.h>
using namespace std;
#define eps 1e-12
int n,m,x,y,ans;
int a[1005];
double target,nums[10005];
bool isprime[1005];
void dfs(int dep,int cnt,double now){//第dep个数字 已经选了cnt个,和为now
    if(cnt == n){
        if(abs(now - target) <= eps)++ans;
        return ;
    }
    if(dep >= m + 1 || now > target + eps)return ;
    double max1,min1;
    max1 = nums[dep] *(double) (n - cnt);
    min1 = nums[m] * (double)(n - cnt);
    if(now + max1 + eps < target || now + min1 > target + eps)return ;
    if(!isprime[dep])dfs(dep + 1,cnt + 1,now + nums[dep]);
    dfs(dep + 1,cnt,now);
}
int main(){
    cin >> n >> m >> x >> y;
    target = x * 1.0 / y;
    isprime[29] = 1;
    isprime[31] = 1;
    isprime[37] = 1;
    isprime[41] = 1;
    isprime[43] = 1;
    isprime[47] = 1;//预处理
    for(int i = 1;i <= m;++i)nums[i] = 1.0 / i;
    dfs(1,0,0);
    cout << ans << endl;
    return 0;//完结撒花
}
posted @ 2026-05-16 20:06  heffo_hard  阅读(15)  评论(0)    收藏  举报