【贪心(?)】2017-03-19realseq

这里写图片描述
分析:
本题解并不严谨,如有证明或bug请指出(最好附反例)
首先,题目中强调了最多包含五位小数,那么就可以将每一个值乘上100000

(注意:乘了100000转整数时候,一定要加0.1,否则会出现精度问题!!巨坑!!)

如果x只在[A,B]中出现了1次,那么就可以看作出现的那个数本身
如果出现了多次,那么一定是某两个数之差。、
因为k十分的小,只有50,所以两两之差最多有只有1000多个
因此,有可能为x的数,也就是可行解的集合最多也就1000多个值

同时,我们还要筛去一些不合法的值:
1、如果为两两之差产生的数,那么这两个数必须是差数的倍数(如3,5的差2就是不合法的,因为3,5不是2的倍数)
2、这个值在[A,B]内每一个倍数都必须出现过。
3、这个值的因数不存在于集合内(否则它一定没有他的因子优)

到这里,我们就得到了一个可行解的集合,现在的任务就是把这个集合尽量缩小。下面就是不科学的地方了:
把集合的值从小到大依次枚举(因为值小的覆盖的数量,一定比值大的多)
如果当前的值可以将覆盖的范围变大,那么就将这个数放入解集。
最后一步,在解集中再找一边,筛去多余的值(即删去这个数覆盖范围不变)
最后的解集就是答案

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 60
using namespace std;
int n;
long long A,B,a[MAXN],al[MAXN*MAXN],vis[MAXN*MAXN],num[MAXN*MAXN],ans;
long long print[MAXN*MAXN];
vector<long long> pos;
long long bit[MAXN];
bool check(long long x){
    for(int i=0;i<pos.size();i++)
        if(x%pos[i]==0)
            return 0;
    long long y=(A+x-1)/x;
    int j=1;
    for(;y*x<=B&&j<=n;y++){
        for(;j<=n;j++)
            if(a[j]==y*x)
                break;
        if(n<j)
            break;
    }
    if(y<=B/x)
        return 0;
    return 1;
}
long long other(int x){
    long long res=0;
    for(int i=0;i<ans;i++)
        if(i!=x)
            res=res|num[i];
    return res;
}
int main(){
    double x;
    long long tot=0;
    freopen("realseq.in","r",stdin);
    freopen("realseq.out","w",stdout);
    bit[0]=1;
    for(int i=1;i<=50;i++)
        bit[i]=bit[i-1]*2;
    SF("%d",&n);
    SF("%I64d%I64d",&A,&B);
    A*=100000;
    B*=100000;
    for(int i=1;i<=n;i++){
        SF("%lf",&x);
        a[i]=1LL*(x*100000.0+0.5);
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<i;j++)
            if(a[i]%(a[i]-a[j])==0&&check(a[i]-a[j])){
                pos.push_back(a[i]-a[j]);
            }
    for(int i=1;i<=n;i++){
        int j=0;
        for(;j<pos.size();j++)
            if(a[i]%pos[j]==0)
                break;
        if(j==pos.size()){
            PF("%I64d.",a[i]/100000);
            PF("%05I64d\n",a[i]%100000);
        }
    }
    sort(pos.begin(),pos.end());
    for(int i=0;i<pos.size();i++){
        for(int j=1;j<=n;j++){
            if(a[j]%pos[i]==0)
                al[i]+=bit[j-1];
        }
    }
    for(int i=0;i<pos.size();i++){
        if((tot|al[i])>tot){
            num[ans]=al[i];
            print[ans++]=pos[i];
            tot=tot|al[i];  
        }
    }
    for(int i=0;i<ans;i++)
        if(other(i)==tot)
            print[i]=-1;
    //PF("(%I64d)",tot)
    for(int i=0;i<ans;i++){
        if(print[i]==-1)
            continue;
        PF("%I64d.",print[i]/100000);
        PF("%05I64d\n",print[i]%100000);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值