加载中…

返回上一页

CSP-S加赛0905

下发文件和题解

A. ZZH的游戏



内存限制:512 MiB 时间限制:1000 ms 标准输入输出
题目类型:传统 评测方式:文本比较

题目描述

ZZH 在和 GVZ 玩游戏。

ZZH 和 GVZ 各有一棵树,每棵树都有 个点。

两棵树上各自有一枚棋子。ZZH 的棋子初始在它树上的点 ,GVZ 的棋子初始在树上的点 。

两人轮流操作。一个人操作时,可以选择不移动自己树上的棋子,也可以选择将自己树上的棋子移动到自己树上相邻的一个点。

当两枚棋子都在所在树的点 上时,游戏结束。游戏的分数是所有时刻中,两个棋子所在的点编号的和的最大值。

ZZH 和 GVZ 会合作让游戏结束时的分数尽量小。两人都极其聪明,因此两人都会采用最优策略。

ZZH 和 GVZ 一共会进行 次游戏,每次游戏的树与之前不同, 也不一定相同,但两人的树的点数一定相等。

你需要求出在每一次游戏中,游戏结束时的分数的最小值。

输入格式

第一行一个非负整数 ,表示游戏的次数。

对于每次游戏,第一行一个正整数 ,表示树的点数。

然后 行,每行两个正整数 ,表示 ZZH 树上的一条边 。

然后 行,每行两个正整数 ,表示 GVZ 树上的一条边 。

然后一行两个正整数 ,分别表示 ZZH 树上棋子初始的位置和 GVZ 树上棋子初始的位置。

输出格式

输出 行,第 行一个整数,表示第 个游戏结束时的最小分数。

样例

样例输入1

1
5
1 5
5 4
3 4
2 4
4 2
5 1
3 4
4 5
3 3

样例输出 1

7

样例 1 解释

首先 ZZH 将棋子移动到 4,接下来 GVZ 不动。

然后 ZZH 将棋子移动到 2,接下来 GVZ 将棋子移动到 4。

然后 ZZH 不动,GVZ 将棋子移动到 5 。

然后 ZZH 不动,GVZ 将棋子移动到 1 。

接下来 ZZH 将棋子移动至 1 即可。

数据范围与提示

对于所有数据,保证: 。

测试点编号 特殊限制
1
2,3,4
5,6,7,8
9,10,11,12 ,两棵树均为随机生成
13,14,15,16,17
18,19,20 无特殊限制

贪心,每次找到一个最优的方案(移左还是移右),把它所有将要到达的点放入优先队列中,直至两边都到1为止.

为了防止重复走某个点,开一个vis记录一下,清空不能用memset,会TLE.

点击查看代码
#include<bits/stdc++.h>
#define ll int
#define rg register
#define rll rg ll
#define maxn 1000001
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
static inline ll read()
{
	rll f=0,x=0;rg char ch=getchar();
	while(ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar();
	return f?-x:x;
}
static inline void write(rll x)
{
	if(x<0) putchar('-'),x=-x;
	if(x>9) write(x/10);putchar(x%10|'0');
}
ll T,n,s,t,ans;
vector<ll> g1[maxn],g2[maxn];
priority_queue<ll,vector<ll>,greater<ll> > q1,q2;
ll vis1[maxn],vis2[maxn];
int main()
{
	T=read();
	while(T--)
	{
		while(!q1.empty()) q1.pop();while(!q2.empty()) q2.pop();n=read();
		for(rll i=1;i<=n;i++) g1[i].clear(),g2[i].clear(),vis1[i]=vis2[i]=0;
		for(rll i=1,a,b;i<n;i++) a=read(),b=read(),g1[a].push_back(b),g1[b].push_back(a);
		for(rll i=1,a,b;i<n;i++) a=read(),b=read(),g2[a].push_back(b),g2[b].push_back(a);
		s=read();t=read(); if(s==1&&t==1) { puts("2"); continue; } ans=s+t;q1.push(s);q2.push(t);
		while(s!=1||t!=1)
		{
			if(q2.empty()||((!q1.empty())&&q1.top()+t<q2.top()+s))//移左比移右更优
			{
				rll x=q1.top();q1.pop();vis1[x]=1;
				ans=max(ans,x+t);s=min(s,x);
				for(rll i=0;i<g1[x].size();i++) if(!vis1[g1[x][i]]) q1.push(g1[x][i]);
			}
			else//移右比移左更优
			{
				rll x=q2.top();q2.pop();vis2[x]=1;
				ans=max(ans,s+x);t=min(t,x);
				for(rll i=0;i<g2[x].size();i++) if(!vis2[g2[x][i]]) q2.push(g2[x][i]);
			}
		}
		write(ans);putn;
	}
	return 0;
}

B. ZZH与背包



内存限制:1024 MiB 时间限制:4000 ms 标准输入输出
题目类型:传统 评测方式:文本比较

题目描述

ZZH 有一个背包。

ZZH有 个物品,第 个物品的体积为 。

ZZH 要去学校,她想带 个物品中的一些去学校。为了使背包不过于空,放入背包中的物品体积总和不能小于 。因为背包有容量上限,所以放入背包中的物品体积总和不能大于 。

ZZH 想知道,她能带去学校的物品的集合一共有多少种。ZZH觉得这个问题太简单了,于是她把这个问题交给了你。

ZZH一共要去 次学校,因为ZZH还有一些必须带的东西(例如显卡),所以每次的 会改变。你需要对于每一个给出的 求出答案。

输入格式

第一行两个非负整数 ,表示物品个数和询问次数。

第二行 个正整数 ,表示每个物体的体积。

然后 行,每行两个正整数 ,表示第 次询问的 。

输出格式

输出 行,第 行一个整数表示第 个询问的方案数。

样例

样例输入 1

4 2
1 2 3 4
3 8
6 6

样例输出 1

11
2

样例1解释

对于第一个询问,除了 外都满足要求。

对于第二组询问,只有 满足要求。

数据范围与提示

对于所有数据,。

测试点编号 特殊限制
1
2,3,4,5
6,7,8
9,10,11
12,13,14,15,16
17,18,19,20

折半搜索这个方法非常巧妙.

利用容斥,大小为l至r的方案数即是大小最大为r的方案数减去大小最大为l-1的方案数.

考虑到n的大小只有40,那么可以把这个40分成两个20. 先排一遍序,于是左半部分是小的数,右半部分是大的数. 把前面一半的所有组合情况搜索出来,后面一半的所有情况也搜索出来,sort一下以保证它的单调性.

在累加答案的时候,用一个双指针. 将右半部分的指针指向第一个小于等于要求的数,枚举左边的所有情况,每次找到左半部分当前数与右半部分的数的和小于等于要求值的最大的右半部分的数. 因为两半的所有情况是单调的,所以右半部分比当前找到的数小的数和左半部分的数的和一定比现在的数小,一定合法. 所以每次加上一个右半部分当前数的位置即可.

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define maxn 5000001
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
static inline ll read()
{
	rll f=0,x=0;rg char ch=getchar();
	while(ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar();
	return f?-x:x;
}
static inline void write(rll x)
{
	if(x<0) putchar('-'),x=-x;
	if(x>9) write(x/10);putchar(x%10|'0');
}
ll n,q,l,r,mid;
ll v[maxn],tot;
ll a[maxn],lena,b[maxn],lenb;
static inline void dfsl(rll x,rll num)
{
	if(x>mid) { a[++lena]=num; return; }
	dfsl(x+1,num);dfsl(x+1,num+v[x]);
}
static inline void dfsr(rll x,rll num)
{
	if(x>n) { b[++lenb]=num; return; }
	dfsr(x+1,num);dfsr(x+1,num+v[x]);
}
static inline ll getans(rll x)
{
	rll t=upper_bound(b+1,b+lenb+1,x)-b-1,ans=0;
	for(rll i=1;i<=lena;i++)
	{
		while(t&&a[i]+b[t]>x) t--;
		if(!t) break;ans+=t;
	}
	return ans;
}
int main()
{
	n=read();q=read();mid=(n>>1);
	for(rll i=1;i<=n;i++) v[i]=read();
	sort(v+1,v+n+1);
	dfsl(1,0);dfsr(mid+1,0);
	sort(a+1,a+lena+1);sort(b+1,b+lenb+1);
	while(q--)
	{
		l=read();r=read();
		write(getans(r)-((!l)?0:getans(l-1)));putn;
	}
	return 0;
}
posted @ 2022-09-06 15:08  1Liu  阅读(106)  评论(0)    收藏  举报