zoukankan      html  css  js  c++  java
  • bzoj 2571: Getting Rid of the Holidays

    Description

    B国的国王Johnny在他在位的短短几年里制定了不少的节日(事实上没超过30个),这些节日是为了尊敬各种各样他所想到的东西而设立的。每过一段固定的时间,一个节日将会被举行(即节日都是周期性的,每个节日的周期可能会不同),并且过节的那一天会普天同庆,将有盛会演奏、歌舞表演。有时候几个节日会在一天同时发生,并且有可能所有节日在同一天发生。如果出现这种情况,节日将被联合庆祝并且举行更大宴会。某一天所有节日都发生了。可能由于玩得太high了,在宴会后,国王Johnny表现开始有点古怪而且他需要与世隔绝几天。 
    在国王Johnny不在的时候(约48小时)你被指定处理B国的政事。最为一个真正的爱国者,你知道这些节日是对人民没有好处的,并且你想在国王Johnny回来之前(Johnny将不会介意,因为他在宴会后会忘记所有事情)删去一些节日。然而悲哀的是,这里的人民不知道什么对他们有好处,什么对他们有坏处,如果你删去了超过k个节日他们将会反抗。你的任务是删除不超过k个节日使得最小的两次有节日的日子之间的间隔最大。 

    Input

    文件的第一行有一个单独的整数T<=200,表示测试数据的组数。接下来有T组测试数据。对于每个测试数据,第一行包含两个整数n和K 
    (1 < = K < n < = 30 ),表示节日的总数和最多可以删除的节日数。接下来的一行包含n个整数表示每个节日的周期,第i个整数表示编号为i的整数的周期,每个节日的周期将不会超过10^18。 

    Output

    对于每个测试数据,输出一行一个数,表示最大的间隔.

    二分答案,两个节日可以共存等价于周期的gcd>=答案,可以用最大独立集判定

    这里给出的是的基于记忆化搜索的实现,时间复杂度上界为每组数据$O((sqrt{2})^{n}nlogn)$,适当剪枝可以通过此题

    #include<bits/stdc++.h>
    typedef long long i64;
    const int M=1<<16|111;
    int T,n,k,vp;
    i64 a[33],gs[33][33],vs[1007],lim;
    i64 gcd(i64 a,i64 b){return b?gcd(b,a%b):a;}
    int e[33],f[M],ed[M],tk=0;
    void maxs(int&a,int b){if(a<b)a=b;}
    int dp(int S,int w){
        if(S<M&&ed[S]==tk)return f[S];
        while(~S>>w&1)--w;
        int v=dp(S&~e[w],w-1)+1;
        if(v<n-k)maxs(v,dp(S^1<<w,w-1));
        if(S<M)ed[S]=tk,f[S]=v;
        return v;
    }
    bool chk(){
        int S=0;
        for(int i=0;i<n;++i){
            e[i]=0;
            for(int j=0;j<n;++j)if(gs[i][j]<lim)e[i]|=1<<j;
            S|=~e[i]&1<<i;
            e[i]|=1<<i;
        }
        ed[0]=++tk,f[0]=0;
        return dp(S,n-1)>=n-k;
    }
    int main(){
        for(scanf("%d",&T);T;--T){
            scanf("%d%d",&n,&k);
            for(int i=0;i<n;++i)scanf("%lld",a+i);
            std::random_shuffle(a,a+n);
            vp=0;
            for(int i=0;i<n;++i)for(int j=0;j<=i;++j)vs[vp++]=gs[j][i]=gs[i][j]=gcd(a[i],a[j]);
            std::sort(vs,vs+vp);
            vp=std::unique(vs,vs+vp)-vs;
            int L=0,R=vp-1,M;
            while(L<R){
                M=L+R+1>>1;
                lim=vs[M];
                if(chk())L=M;
                else R=M-1;
            }
            printf("%lld
    ",vs[L]);
        }
        return 0;
    }
  • 相关阅读:
    P1342 请柬
    P1186 玛丽卡
    Scala 中下划线的用法
    IDEA2017 maven Spark HelloWorld项目(本地断点调试)
    Spark内存管理详解
    Spark基础知识
    scala基本语法
    分布式锁的一点理解
    Redis并发问题
    redis集群原理
  • 原文地址:https://www.cnblogs.com/ccz181078/p/7245013.html
Copyright © 2011-2022 走看看