机房模拟20180814

日常................

\机房模拟20180814_第1张图片

LIS裸题............真的不需要题解吧......

设定一个数组low[i]表示长度为i的LIS的最小的结尾,我们可以发现low内的数组一定是单增的,所以我们可以在a【i】大于末项的时候更新,然后将每一个不大于末项的a[i]用lower_bound二分找到其在low中的位置然后更新

最后输出low数组的长度就好了

#include
#include
const int MAXN=1e5+5;
const int INF=0x7fffffff;
int low[MAXN];
int a[MAXN];
int n;
int ans;
int main()
{
	//std::freopen("lis.in","r",stdin);
	//std::freopen("lis.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]); 
        low[i]=INF;
    }
    low[1]=a[1]; 
    ans=1;
    for(int i=2;i<=n;i++)
    {
        if(a[i]>low[ans])
        {
        	low[++ans]=a[i];
        }
        else
        {
        	low[std::lower_bound(low+1,low+1+ans,a[i])-low]=a[i];
        }
    }
    printf("%d\n",ans);
    return 0;
}

 T2

机房模拟20180814_第2张图片

树形dp,然而我用状压的假算法苟到了40分............

我们定义dp[u][i]为在u为根的子树当中,选取i个点构成联通块需要的最小割边数量

转移方程简单的要死........自己都不知道考试的时候为什么想不到

dp[u][i]=std::min(dp[u][i]+1,min(dp[u][i-j]+dp[v][j]))

全部枚举直接dp就完成了

#include
#include
#include
const int MAXN=150+5;
const int INF=1e9+7;
class Edge
{
	public:
		int nxt;
		int to;
}edge[MAXN<<1];
int head[MAXN]; 
int num;
void add(int from,int to)
{
	edge[++num].nxt=head[from];
	edge[num].to=to;
	head[from]=num;
}
int n,k;
int siz[MAXN];
int dp[MAXN][MAXN];
int ans=INF;
void dfs(int u,int f)
{
	std::memset(dp[u],63,sizeof(dp[u]) );
	siz[u]=1;
	dp[u][1]=0;
	for(int i=head[u];i;i=edge[i].nxt)
	{
		int v=edge[i].to;
		if(v==f)
		{
			continue;
		}
		dfs(v,u);
		siz[u]+=siz[v];
		for(int i=k;i>=1;i--) 
		{
			int tmp=dp[u][i]+1;
            for(int j=1;j

T3

机房模拟20180814_第3张图片

轮廓线裸题,全班AC率最高的题目.......

定义dp[i][s]为状态为s,取到第i行的方案数,然后按照正常的轮廓线更新就好了

具体轮廓线的套路比较复杂,在这里就不讲了

详情可以参见这篇博客

https://blog.csdn.net/cyendra/article/details/38171319

代码实现非常简单

#include
#include
#include
#include
#define LL long long
const int MAXN=15;
LL dp[2][1<r)
	std::swap(r,c);
    memset(dp,0,sizeof(dp));
    now=0;
    dp[now][(1<

T4

机房模拟20180814_第4张图片

 

 背包裸题

设dp[k][t]表示现在选取了价值总和为k的集合中是否能包含t

而新添加的元素一定对k产生影响,一定会加上a[i]

而对于t可能影响可能不影响

所以直接转移就好

dp[j+a[i]][t]|=dp[j][t];
dp[j+a[i]][t+a[i]]|=dp[j][t];

#include
#include
const int MAXN=505;
bool dp[MAXN][MAXN];
int a[MAXN];
int main()
{
	//std::freopen("coin.in","r",stdin);
	//std::freopen("coin.out","w",stdout);
	int n,k;
	std::scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++)
	{
		std::scanf("%d",a+i);
	}
	dp[0][0]=1;
	for(int i=1;i<=n;i++)
	{
		for(int j=k-a[i];j>=0;j--)
		{
			for(int t=j;t>=0;t--)
			{
				if(dp[j][t])
				{
					dp[j+a[i]][t]|=dp[j][t];
					dp[j+a[i]][t+a[i]]|=dp[j][t];
				}
			}
		}
	}
	int cnt=0;
	for(int i=0;i<=k;i++)
	{
		if(dp[k][i])
		{
			cnt++;
		}
	}
	std::printf("%d\n",cnt);
	for(int i=0;i<=k;i++)
	{
		if(dp[k][i])
		{
			std::printf("%d ",i);
		}
	}
	std::printf("\n");
	return 0;
}

 

你可能感兴趣的:(机房模拟20180814)