NOI2015 题解

D1T1 程序自动分析

题目大意:给定109个变量和n个等于/不等于的关系,判断能否存在一组解满足所有关系

并查集傻逼题,NOIP小孩都会做

离散化一下,然后把相等的都用并查集并起来,判断每对不等关系是不是在同一并查集中就行了

代码没拷回来,懒得再写一遍了

D2T2 软件包管理器

题目大意:给定一棵有根树,每个点有黑白两种颜色,初始都为白色,每次进行以下两种操作:

1.将某个点所在的子树染白

2.将某个点到根路径上的点染黑

求每次操作后有多少点的颜色发生了改变

树剖傻逼题,NOIP小孩都会做

维护一棵有根树,支持链查询,链修改,子树查询,子树修改

显然链剖就行了

代码也没拷回来,懒得再写一遍了

D3T3 寿司晚宴

题目大意:给定2...n一共n?1个数字,第一个人选择一些数字,第二个人选择一些数字,要求第一个人选的任意一个数字和第二个人选择的任意一个数字都互质,求方案数

n≤500

DP傻逼题,我竟然不会做

首先我们把一个数字看成这样一坨东西:

小于500???√的质数只有8个,我们开一个28的数组记录每个质数是否出现

大于500???√的质数只会在这个数字中出现最多一个(即一个数字中最多只有一个大于500???√的质因数),我们把数字按照这个质数分类,没有大于500???√的质因数的数每个自成一类

那么显然一类数最多只有一个人能取 两个人都取同一类数的话就会出现不互质的情况

然后我们就可以DP辣!!

令fi,j表示第一个人选择的质数集合为i,第二个人选择的质数集合为j的方案数,其中i,j的取值范围为[0,28),二进制的第i位为1表示第i个质数已经取到了

令gi,j,k表示第i+1个人选择了这一类的数(可以不选)后第一个人选择的质数集合为j,第二个人选择的质数集合为k的方案数

枚举每一类数,首先将f数组复制一份给g0和g1,然后这一类数中的每个数字来更新g0和g1,最后用g0+g1?f替换f数组即可

什么你问我为何要减掉f?很简单因为这一类数两个人都不选的状态在g0和g1中都出现了啊~

时间复杂度O(500?216)

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 550
using namespace std;
const int prime[]={2,3,5,7,11,13,17,19};
int n,p;
int f[1<<8][1<<8],g[2][1<<8][1<<8];
pair<int,int> stack[550];
int main()
{   int i,j,k;
    cin>>n>>p;
    for(i=1;i<=n;i++)
    {
        int temp=i;
        for(j=0;j<8;j++)
            if(temp%prime[j]==0)
            {
                stack[i].second|=1<<j;
                while(temp%prime[j]==0)
                    temp/=prime[j];
            }
        stack[i].first=temp;
    }
    sort(stack+2,stack+n+1);
    f[0][0]=1;
    for(i=2;i<=n;i++)
    {
        if( i==2 || stack[i].first==1 || stack[i].first!=stack[i-1].first )
        {
            memcpy(g[0],f,sizeof f);
            memcpy(g[1],f,sizeof f);
        }
        for(j=255;~j;j--)
            for(k=255;~k;k--)
            {
                if( (stack[i].second&k)==0 )
                    (g[0][j|stack[i].second][k]+=g[0][j][k])%=p;
                if( (stack[i].second&j)==0 )
                    (g[1][j][k|stack[i].second]+=g[1][j][k])%=p;
            }
        if( i==n || stack[i].first==1 || stack[i].first!=stack[i+1].first )
        {
            for(j=0;j<1<<8;j++)
                for(k=0;k<1<<8;k++)
                    f[j][k]=((g[0][j][k]+g[1][j][k]-f[j][k])%p+p)%p;
        }
    }
    int ans=0;
    for(j=0;j<1<<8;j++)
        for(k=0;k<1<<8;k++)
            if( (j&k)==0 )
                (ans+=f[j][k])%=p;
    cout<<ans<<endl;
    return 0;
}

D2T1 荷马史诗

题目大意:给定一篇文章中每个字母的出现次数,要求为每一个字母设计一个k进制编码使得不存在一个字母是另一个字母的前缀且总长度最小,在此基础上要求最长的字母最短

k=2时第一问就是裸的哈夫曼树,不知道的可以想象合并果子

k-哈夫曼树就是一次合并k个,如果有零头的话就先把零头合并

最长的字母最短就是每次找高度最小的树合并

别问我怎么证明,我连合并果子都不会证…

代码:

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
struct abcd{
    long long size;
    int dpt;
    abcd() {}
    abcd(long long _,int __):
        size(_),dpt(__) {}
    friend bool operator < (const abcd &x,const abcd &y)
    {
        if(x.size!=y.size)
            return x.size>y.size;
        return x.dpt>y.dpt;
    }
};
int n,k,ans2;
long long ans1;
priority_queue<abcd> heap;
void Merge(int cnt)
{
    long long _size=0;
    int _dpt=0;
    while(cnt--)
    {
        abcd temp=heap.top();heap.pop();
        _size+=temp.size;
        _dpt=max(_dpt,temp.dpt);
    }
    ans1+=_size;
    ans2=max(ans2,++_dpt);
    heap.push(abcd(_size,_dpt));
}
int main()
{
    int i;long long x;
    cin>>n>>k;
    for(i=1;i<=n;i++)
    {
        scanf("%lld",&x);
        heap.push(abcd(x,0));
    }
    if( (n-1)%(k-1)+1!=1 && n!=1 )
        Merge( min( (n-1)%(k-1)+1 , n ) );
    while(heap.size()>1)
        Merge( min( k , (int)heap.size() ) );
    cout<<ans1<<‘\n‘<<ans2<<endl;
    return 0;
}

D2T2 品酒大会

题目大意:给定一个长度为n字符串,每个后缀有一个权值f,对于l=0...n?1输出Lcp(i,j)≥l(i<j)的后缀对(i,j)的个数以及最大的fi?fj

神木韵律的超n级弱化版= =?

求出后缀数组后从大到小枚举height值,然后对于每个height值,两端的集合中任意一对后缀的LCP都是这个height,我们统计答案之后合并两端的集合,用并查集维护即可

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 300300
using namespace std;

int n;
char s[M];
long long ans1[M],ans2[M];

namespace Suffix_Array{
    int sa[M],rank[M],height[M];
    int X[M],Y[M],temp[M],tot;
    void Get_Rank()
    {
        static int sum[M];
        int i;
        for(i=1;i<=n;i++)
            sum[s[i]]++;
        for(i=1;i<=200;i++)
            sum[i]+=sum[i-1];
        for(i=n;i;i--)
            sa[sum[s[i]]--]=i;
        for(i=1;i<=n;i++)
        {
            if( i==1 || s[sa[i-1]]!=s[sa[i]] )
                ++tot;
            rank[sa[i]]=tot;
        }
    }
    void Radix_Sort(int key[],int order[])
    {
        static int sum[M];
        int i;
        for(i=0;i<=n;i++)
            sum[i]=0;
        for(i=1;i<=n;i++)
            sum[key[i]]++;
        for(i=1;i<=n;i++)
            sum[i]+=sum[i-1];
        for(i=n;i;i--)
            temp[sum[key[order[i]]]--]=order[i];
        for(i=1;i<=n;i++)
            order[i]=temp[i];
    }
    void Get_Height()
    {
        int i,j,k;
        for(i=1;i<=n;i++)
        {
            if(rank[i]==1)
                continue;
            j=sa[rank[i]-1];
            k=max(0,height[rank[i-1]]-1);
            while(s[i+k]==s[j+k])
                ++k;
            height[rank[i]]=k;
        }
    }
    void Prefix_Doubling()
    {
        int i,j;
        Get_Rank();
        for(j=1;j<=n;j<<=1)
        {
            for(i=1;i<=n;i++)
            {
                X[i]=rank[i];
                Y[i]=i+j>n?0:rank[i+j];
                sa[i]=i;
            }
            Radix_Sort(Y,sa);
            Radix_Sort(X,sa);
            for(tot=0,i=1;i<=n;i++)
            {
                if( i==1 || X[sa[i]]!=X[sa[i-1]] || Y[sa[i]]!=Y[sa[i-1]] )
                    ++tot;
                rank[sa[i]]=tot;
            }
        }
        Get_Height();
    }
}

namespace Union_Find_Set{
    int fa[M],rank[M],size[M],max_val[M],min_val[M];
    int Find(int x)
    {
        if(!fa[x])
            size[x]=1,fa[x]=x;
        if(fa[x]==x)
            return x;
        return fa[x]=Find(fa[x]);
    }
    void Union(int x,int y)
    {
        x=Find(x);y=Find(y);
        if(x==y) return ;
        if(rank[x]>rank[y])
            swap(x,y);
        if(rank[x]==rank[y])
            ++rank[y];
        fa[x]=y;size[y]+=size[x];
        max_val[y]=max(max_val[x],max_val[y]);
        min_val[y]=min(min_val[x],min_val[y]);
    }
}

bool Compare(int x,int y)
{
    using namespace Suffix_Array;
    return height[x]>height[y];
}

int main()
{
    using namespace Suffix_Array;
    using namespace Union_Find_Set;
    int i,x,y;
    cin>>n;scanf("%s",s+1);
    Prefix_Doubling();
    for(i=1;i<=n;i++)
    {
        scanf("%d",&x);
        max_val[Suffix_Array::rank[i]]=min_val[Suffix_Array::rank[i]]=x;
    }
    static int a[M];
    for(i=2;i<=n;i++)
        a[i-1]=i;
    sort(a+1,a+n,Compare);
    memset(ans2,0xef,sizeof ans2);
    for(i=1;i<n;i++)
    {
        x=Find(a[i]-1),y=Find(a[i]);
        ans1[height[a[i]]]+=(long long)size[x]*size[y];
        ans2[height[a[i]]]=max(ans2[height[a[i]]],(long long)min_val[x]*min_val[y]);
        ans2[height[a[i]]]=max(ans2[height[a[i]]],(long long)min_val[x]*max_val[y]);
        ans2[height[a[i]]]=max(ans2[height[a[i]]],(long long)max_val[x]*min_val[y]);
        ans2[height[a[i]]]=max(ans2[height[a[i]]],(long long)max_val[x]*max_val[y]);
        Union(x,y);
    }
    for(i=n-1;~i;i--)
    {
        ans1[i]+=ans1[i+1];
        ans2[i]=max(ans2[i],ans2[i+1]);
    }
    for(i=0;i<n;i++)
        printf("%lld %lld\n",ans1[i],ans1[i]==0?0:ans2[i]);
    return 0;
}

D2T3 小园丁与老司机

题目大意:给定平面上n个点,从原点出发,每次可以走到左、左上、上、右上、右的每个方向上第一个能到的点,一个点走过即消失,求:

1.最多能到达多少个点

2.输出任意一组方案

3.将所有方案中的左上、上、右上的路径连起来,求最小路径覆盖

DP,记录方案,建图跑最小流,这题只有细节,只有细节……

我的代码写了个费用流,被第7个点卡出翔过不了……

#include <map>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 50500
#define S (M-1)
#define T (M-2)
#define INF 0x3f3f3f3f
using namespace std;

struct Point{
    int x,y,id;
    friend istream& operator >> (istream &_,Point &p)
    {
        return scanf("%d%d",&p.x,&p.y),_;
    }
    friend bool operator < (const Point &p1,const Point &p2)
    {
        if( p1.y!=p2.y )
            return p1.y < p2.y ;
        return p1.x < p2.x ;
    }
}points[M];

int n,ans1,ans1_ed,ans2;
int f[M],g[M],from[M],_from[M];

map<int,int> m1,m2,m3;

namespace Max_Cost_Max_Flow{
    struct abcd{
        int to,flow,cost,next;
    }table[2002002];
    int head[M],tot=1;
    void Add(int x,int y,int f,int c)
    {
        table[++tot].to=y;
        table[tot].flow=f;
        table[tot].cost=c;
        table[tot].next=head[x];
        head[x]=tot;
    }
    void Link(int x,int y,int f,int c)
    {
        Add(x,y,f,c);
        Add(y,x,0,-c);
    }
    bool Edmonds_Karp()
    {
        static int q[65540],flow[M],cost[M],from[M];
        static unsigned short r,h;
        static bool v[M];
        int i;
        memset(cost,0xef,sizeof cost);
        flow[S]=INF;cost[S]=0;q[++r]=S;
        while(r!=h)
        {
            int x=q[++h];v[x]=false;
            for(i=head[x];i;i=table[i].next)
                if(table[i].flow&&cost[table[i].to]<cost[x]+table[i].cost)
                {
                    cost[table[i].to]=cost[x]+table[i].cost;
                    flow[table[i].to]=min(flow[x],table[i].flow);
                    from[table[i].to]=i;
                    if(!v[table[i].to])
                        v[table[i].to]=true,q[++r]=table[i].to;
                }
        }
        if(cost[T]<=0) return false;
        ans2+=flow[T];
        for(i=from[T];i;i=from[table[i^1].to])
            table[i].flow-=flow[T],table[i^1].flow+=flow[T];
        return true;
    }
}

int main()
{
    using namespace Max_Cost_Max_Flow;
    int i,j;
    cin>>n;
    for(i=1;i<=n;i++)
        cin>>points[i],points[i].id=i;
    sort(points+1,points+n+1);
    static int stack[M],top;
    memset(f,0xef,sizeof f);f[0]=0;
    for(i=0;i<=n;i++)
    {
        if(m1.find(points[i].x)!=m1.end())
        {
            int temp=m1[points[i].x];
            if(f[temp]+1>f[i]) f[i]=f[temp]+1,from[i]=temp;
        }
        m1[points[i].x]=i;

        if(m2.find(points[i].x+points[i].y)!=m2.end())
        {
            int temp=m2[points[i].x+points[i].y];
            if(f[temp]+1>f[i]) f[i]=f[temp]+1,from[i]=temp;
        }
        m2[points[i].x+points[i].y]=i;

        if(m3.find(points[i].x-points[i].y)!=m3.end())
        {
            int temp=m3[points[i].x-points[i].y];
            if(f[temp]+1>f[i]) f[i]=f[temp]+1,from[i]=temp;
        }
        m3[points[i].x-points[i].y]=i;

        stack[++top]=i;
        if( i==n || points[i+1].y!=points[i].y )
        {
            static int _f[M];
            for(j=1;j<=top;j++)
            {
                _f[stack[j]]=f[stack[j]];
                _from[stack[j]]=from[stack[j]];
            }
            int max_pos=-1;
            for(j=2;j<=top;j++)
            {
                if( max_pos==-1 || _f[stack[j-1]]>_f[stack[max_pos]] )
                    max_pos=j-1;
                if( _f[stack[max_pos]]+(j-1)>f[stack[j]] )
                    f[stack[j]]=_f[stack[max_pos]]+(j-1),from[stack[j]]=stack[max_pos];
            }
            max_pos=-1;
            for(j=top-1;j;j--)
            {
                if( max_pos==-1 || _f[stack[j+1]]>_f[stack[max_pos]] )
                    max_pos=j+1;
                if( _f[stack[max_pos]]+(top-j)>f[stack[j]] )
                    f[stack[j]]=_f[stack[max_pos]]+(top-j),from[stack[j]]=stack[max_pos];
            }

            for(j=1;j<=top;j++)
                if(f[stack[j]]>ans1)
                    ans1=f[stack[j]],ans1_ed=stack[j];

            top=0;
        }
    }

    cout<<ans1<<endl;
    bool flag=false;
    while(ans1_ed)
    {
        stack[++top]=points[ans1_ed].id;
        if(flag)
        {
            flag=false;
            ans1_ed=_from[ans1_ed];
            continue;
        }
        if(points[ans1_ed].y==points[from[ans1_ed]].y)
        {
            if(ans1_ed>from[ans1_ed])
            {
                for(i=ans1_ed-1;i!=from[ans1_ed];i--)
                    stack[++top]=points[i].id;
                for(i--;points[i].y==points[ans1_ed].y;i--);
                for(i++;i!=from[ans1_ed];i++)
                    stack[++top]=points[i].id;
            }
            else
            {
                for(i=ans1_ed+1;i!=from[ans1_ed];i++)
                    stack[++top]=points[i].id;
                for(i++;points[i].y==points[ans1_ed].y;i++);
                for(i--;i!=from[ans1_ed];i--)
                    stack[++top]=points[i].id;
            }
            flag=true;
        }
        ans1_ed=from[ans1_ed];
    }
    //cout<<top<<endl;
    while(top)
        printf("%d ",stack[top--]);
    puts("");

    m1.clear();
    m2.clear();
    m3.clear();

    memcpy(g,f,sizeof g);

    for(i=n;~i;i--)
    {
        f[i]=(i!=0);
        if(m1.find(points[i].x)!=m1.end())
        {
            int temp=m1[points[i].x];
            f[i]=max(f[temp]+(i!=0),f[i]);
            //printf("%d\n",g[i]+f[temp]);
            if(g[i]+f[temp]==ans1)
            {
                Link(temp,i,1,1);
                Link(temp,i,INF,0);
            }
        }
        m1[points[i].x]=i;

        if(m2.find(points[i].x+points[i].y)!=m2.end())
        {
            int temp=m2[points[i].x+points[i].y];
            f[i]=max(f[temp]+(i!=0),f[i]);
            //printf("%d\n",g[i]+f[temp]);
            if(g[i]+f[temp]==ans1)
            {
                Link(temp,i,1,1);
                Link(temp,i,INF,0);
            }
        }
        m2[points[i].x+points[i].y]=i;

        if(m3.find(points[i].x-points[i].y)!=m3.end())
        {
            int temp=m3[points[i].x-points[i].y];
            f[i]=max(f[temp]+(i!=0),f[i]);
            //printf("%d\n",g[i]+f[temp]);
            if(g[i]+f[temp]==ans1)
            {
                Link(temp,i,1,1);
                Link(temp,i,INF,0);
            }
        }
        m3[points[i].x-points[i].y]=i;

        stack[++top]=i;
        if( i==0 || points[i-1].y!=points[i].y )
        {
            static int _f[M];
            for(j=1;j<=top;j++)
                _f[stack[j]]=f[stack[j]];
            int max_pos=-1;
            for(j=2;j<=top;j++)
            {
                if( max_pos==-1 || _f[stack[j-1]]+(top-j+1)>_f[stack[max_pos]]+(top-max_pos) )
                    max_pos=j-1;
                if( _f[stack[max_pos]]+(top-max_pos)>f[stack[j]] )
                    f[stack[j]]=_f[stack[max_pos]]+(top-max_pos);
            }
            max_pos=-1;
            for(j=top-1;j;j--)
            {
                if( max_pos==-1 || _f[stack[j+1]]+(j)>_f[stack[max_pos]]+(max_pos-1) )
                    max_pos=j+1;
                if( _f[stack[max_pos]]+(max_pos-1)>f[stack[j]] )
                    f[stack[j]]=_f[stack[max_pos]]+(max_pos-1);
            }
            top=0;
        }
    }

    m1.clear();
    m2.clear();
    m3.clear();
    /*
    for(i=0;i<=n;i++)
        printf("%d\n",f[i]+g[i]);

    for(i=0;i<=n;i++)
    {
        if(m1.find(points[i].x)!=m1.end())
        {
            int temp=m1[points[i].x];
            if(g[temp]+f[i]==ans1)
            {
                Link(temp,i,1,1);
                Link(temp,i,INF,0);
            }
        }
        m1[points[i].x]=i;

        if(m2.find(points[i].x+points[i].y)!=m2.end())
        {
            int temp=m2[points[i].x+points[i].y];
            if(g[temp]+f[i]==ans1)
            {
                Link(temp,i,1,1);
                Link(temp,i,INF,0);
            }
        }
        m2[points[i].x+points[i].y]=i;

        if(m3.find(points[i].x-points[i].y)!=m3.end())
        {
            int temp=m3[points[i].x-points[i].y];
            if(g[temp]+f[i]==ans1)
            {
                Link(temp,i,1,1);
                Link(temp,i,INF,0);
            }
        }
        m3[points[i].x-points[i].y]=i;
    }
    */
    for(i=0;i<=n;i++)
    {
        Link(S,i,INF,0);
        Link(i,T,INF,0);
    }
    while( Edmonds_Karp() );
    cout<<ans2<<endl;
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-07 14:47:23

NOI2015 题解的相关文章

【NOI2015】寿司晚会 题解(状压DP)

[问题描述] 为了庆祝 NOI 的成功开幕,主办方为大家准备了一场寿司晚宴.小 G 和小 W 作为参加 NOI 的选手,也被邀请参加了寿司晚宴. 在晚宴上,主办方为大家提供了 n?1 种不同的寿司,编号 1,2,3,?, n?1, 其中第 i 种寿司的美味度为 i+1  (即寿司的美味度为从 2 到 n ). 现在小 G 和小 W 希望每人选一些寿司种类来品尝,他们规定一种品尝方案 为不和谐的当且仅当:小 G 品尝的寿司种类中存在一种美味度为 x 的寿司,小 W 品尝的寿司中存在一种美味度为 y

[总结+题解]NOI2015

// 此博文为迁移而来,写于2015年7月20日,不代表本人现在的观点与看法.原始地址:http://blog.sina.com.cn/s/blog_6022c4720102w6u7.html 1.总结 这次参加的网上同步赛,感觉和正式考试大不相同啊!考试的时候一点都没有状态……所以结果也是凄惨的.总的而言,据说这次考试也是如同去年NOI一样的水,Day2还是可以的,Day1说实话我也觉得好水,然而这并没有什么卵用.NOI2014还没有看过,最近去体验一下吧. 因为参加的同步赛,其实也没有什么过

BZOJ4196:[NOI2015]软件包管理器——题解

http://www.lydsy.com/JudgeOnline/problem.php?id=4196 https://www.luogu.org/problemnew/show/P2146 你决定设计你自己的软件包管理器.不可避免地,你要解决软件包之间的依赖问题.如果软件包A依赖软件包B,那么安装软件包A以前,必须先安装软件包B.同时,如果想要卸载软件包B,则必须卸载软件包A.现在你已经获得了所有的软件包之间的依赖关系.而且,由于你之前的工作,除0号软件包以外,在你的管理器当中的软件包都会依

[Noi2015]软件包管理器 题解

题目大意: 有n个软件安装包,除第一个以外,其他的要在另一个安装包的基础上安装,且无环,问在安装和卸载某个软件包时,这个操作实际上会改变多少个软件包的安装状态. 思路: 可构成树,用树链剖分,线段树.已安装的为1,未安装的为0.对于安装操作,就是询问x到0的路径上0的个数,然后把这个路径赋为1:对于卸载操作,就是询问x的子树中1的个数,然后把子树赋为0. 代码: 1 #include<cstdio> 2 #include<iostream> 3 #define M 800500 4

【题解】NOI2015寿司晚宴

想好久啊+不敢写啊--但果然人还是应当勇敢自信,只有坚定地去尝试,才会知道最后的结果.1A真的太开心啦,不过好像我的做法还是比较复杂的样子--理解起来应该算是比较容易好懂的类型,大家可以参考一下思路~ 首先我们先考虑一下简单的30分算法:30以内的质数只有十个左右,可以利用状压表示出两个人所选择的集合,再通过寿司转移即可.之后的大数据呢?我们发现不能这样做是因为之后的质数越来越多,状压的空间就开不下了. 这时要注意到一个性质:对于1~n内的每一个数而言,都可以分解成若干个<sqrt(n)的质数之

bzoj4195[Noi2015]程序自动分析

bzoj4195[Noi2015]程序自动分析 题意: t组数据,每组n个给出两个变量是相等还是不等的约束条件,要求判断是否能满足.n≤1000000,变量数量≤109 题解: 先离散化,然后只处理相等条件用并查集维护“相等集合”,接着对每个不相等条件判断是否在一个集合,是的话则说明不满足. 代码: 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <queue&g

noi2015 day1 T2软件包管理器

noi2015 软件包管理器 Description Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软件包,同时自动解决所有的依赖(即下载安装这个软件包的安装所依赖的其它软件包),完成所有的配置.Debian/Ubuntu使用的apt-get,Fedora/CentOS使用的yum,以及OSX下可用的homebrew都是优秀的软件包管理器. 你决定设计你自己的软件包管理器.不可避免地,你要解决软件包

【BZOJ4197】[Noi2015]寿司晚宴 状压DP+分解质因数

[BZOJ4197][Noi2015]寿司晚宴 Description 为了庆祝 NOI 的成功开幕,主办方为大家准备了一场寿司晚宴.小 G 和小 W 作为参加 NOI 的选手,也被邀请参加了寿司晚宴. 在晚宴上,主办方为大家提供了 n−1 种不同的寿司,编号 1,2,3,…,n−1,其中第 i 种寿司的美味度为 i+1 (即寿司的美味度为从 2 到 n). 现在小 G 和小 W 希望每人选一些寿司种类来品尝,他们规定一种品尝方案为不和谐的当且仅当:小 G 品尝的寿司种类中存在一种美味度为 x

Bzoj 4196: [Noi2015]软件包管理器 树链剖分

4196: [Noi2015]软件包管理器 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 721  Solved: 419[Submit][Status][Discuss] Description Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软件包,同时自动解决所有的依赖(即下载安装这个软件包的安装所依赖的其它软件包),完成所有的配置.Debian