topcoder srm 691 div1 -3

1、给定一个$n$个顶点$n$个边的图,边是$(i,a_{i})$,顶点编号$[0,n-1]$。增加一个顶点$n$,现在选出一个顶点集$M$,对于任意的在$M$中 的顶点$x$,去掉边$(x,a_{x})$,增加边$(x,n)$。最后使得顶点0和1相连。有多少种$M$?

思路:设从0开始可以遍历的顶点集合为$A$,从1可以遍历的顶点集合为$B$,$C=A\bigcap B$。令$A^{'}=A-C,B^{'}=B-C$。那么有下面的情况:

(1)在$C$中选择一些点(至少一个),从$A^{'},B^{'}$中任意选点;

(2)在$C$中不选择点,从$A^{'},B^{'}$中任意选点(不能为空);

(3)假设$C$不为空,那么可以不从$A^{'},B^{'},C$中选择。

对于不在$A^{'},B^{'},C$中的点都是随便选。

#include <stdio.h>
#include <string>
#include <stack>
#include <vector>
#include <string.h>
#include <algorithm>
#include <assert.h>
using namespace std;

const int N=55;

#define B(x) (1ll<<(x))


class Sunnygraphs {
public:
	long long count(vector<int> a)
	{
	    int n=(int)a.size();
	    vector<int> mask(n);
	    for(int i=0;mask[i]<1;i=a[i]) mask[i]|=1;
	    for(int i=1;mask[i]<2;i=a[i]) mask[i]|=2;
	    int c[4]={0,0,0,0};
	    for(int i=0;i<n;++i) ++c[mask[i]];

	    long long ans=0;
	    ans+=(B(c[3])-1)*B(c[1])*B(c[2]);
	    ans+=(B(c[1])-1)*(B(c[2])-1);
	    if(c[3]) ++ans;
	    ans<<=c[0];
	    return ans;
	}
};

2、给定$n$组数字$(a_{i},b_{i})$,$n$为偶数。现在重新排列这$n$组数字,得到新的$(A_{i},B_{i})$,使得下面的值最大:

$ans=\sum_{i=1}^{\frac{n}{2}}(B_{i}\sum_{j=1}^{i}A_{j})+\sum_{i=\frac{n}{2}+1}^{n}(B_{i}(X+\sum_{j=1}^{i}A_{j}))$

其中$2\leq n\leq 50,1\leq a_{i}\leq100000,1\leq b_{i}\leq10,0\leq X\leq 100000$

思路:现在考虑考虑最后分在前一半的两组$(A_{i},B_{i}),(A_{j},B_{j})$,若$i$在前优于$j$在前,那么$A_{i}B_{i}+(A_{i}+A_{j})B_{j}\geq A_{j}B_{j}+(A_{i}+A_{j})B_{i}$,即$A_{i}B_{j}\geq A_{j}B_{i}$。

由于$b_{i}$较小,现在枚举最后后一半的数字的所有的$A_{i}$之和$S$,那么现在对于一个数对,可以直接枚举它在前一半还是后一半(现在不管它在前一半还是后一半都可以直接计算对答案的贡献),这样可以进行动态规划。令$f[i][j][k]$表示现在已经考虑了$i$个数字,后一半数字的个数为$j$,后一半数字的$B$之和为$k$能得到的最大值,答案为$f[n][n/2][S]$。

#include <stdio.h>
#include <string>
#include <stack>
#include <vector>
#include <string.h>
#include <algorithm>
#include <assert.h>
using namespace std;


int cmp(pair<int,int> a,pair<int,int> b)
{
    return a.first*b.second<b.first*a.second;
}


int f[55][33][505];

int A[55],B[55];

void up(int &x,int y)
{
    if(x<y) x=y;
}

int n;

void DP(const int NextSumB,const int X)
{
    memset(f,-1,sizeof(f));
    f[0][0][0]=0;
    int pre=0;
    for(int i=1;i<=n;++i)
    {
        pre+=B[i];
        for(int j=0;j<=n/2;++j) for(int k=0;k<=pre;++k)
        {
            if(f[i-1][j][k]>=0)
            {
                up(f[i][j][k],f[i-1][j][k]+A[i]*(pre-k)+A[i]*NextSumB);
                up(f[i][j+1][k+B[i]],f[i-1][j][k]+A[i]*B[i]+A[i]*k+X*B[i]);
            }
        }
    }
}

class Moneymanager {
	public:
	int getbest(vector<int> a,vector <int> b,int X) {
	    vector<pair<int,int> > p;
	    n=(int)a.size();
	    int sum=0;
	    for(int i=0;i<n;++i) {
            p.push_back(make_pair(a[i],b[i]));
            sum+=b[i];
	    }
	    sort(p.begin(),p.end(),cmp);
	    for(int i=1;i<=n;++i)
        {
            A[i]=p[i-1].first;
            B[i]=p[i-1].second;
        }

	    int ans=0;
	    for(int i=0;i<=sum;++i)
        {
            DP(i,X);
            ans=max(ans,f[n][n/2][i]);
        }

        return ans;
	}
};

  

 

posted @ 2017-05-25 11:14  朝拜明天19891101  阅读(308)  评论(0编辑  收藏  举报