2021.8.25 提高组模拟赛

100+100+15 。第一题挺水,第二题花的时间太多了(一开始方向走错了),第三题真的没想到是个区间dp。悬吊吊的班一。

- T1 夏洛特

题面

⼄坂有宇为了收集全世界的能⼒,需要在进⾏旅⾏。

⼄坂有宇的初始坐标为(0,0)初始时间为0,他对⾃⼰的旅⾏做了 个计划,具体的说,对于\(1\le i\le n\),他希望在\(t_i\)时刻恰好到达坐标(\(x_i,y_i\))。对于⼀个时刻 ,如果坐标为(\(x,y\)),那么在
时刻,可以到达上下左右中的任意⼀个,但是不能停留在原地。

有宇希望知道他能不能达成他的计划。多组数据。

解法

按时间排序,然后看每一个点是否可以从上一个点走过来。“可以”的定义是时间“刚刚好够”或者比“刚刚好”的时间多偶数个时间单位。难度……还可以吧。

#include<cstdio>
#include<algorithm>
//#define zczc
using namespace std;
const int N=100010;
inline void read(int &wh){
    wh=0;int f=1;char w=getchar();
    while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
    while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar(); }
    wh*=f;return;
}

int m;
inline int abs(int s1){
	return s1<0?-s1:s1;
}
struct point{
	int t,x,y;
}a[N];
inline bool operator <(point s1,point s2){
	return s1.t<s2.t;
}

signed main(){
	
	#ifdef zczc
	freopen("in.txt","r",stdin);
	#endif
	
	int test;read(test);
	while(test--){
		read(m);
		a[0].t=a[0].x=a[0].y=0;
		for(int i=1;i<=m;i++){
			read(a[i].t);
			read(a[i].x);
			read(a[i].y);
		}
		sort(a,a+m+1);
		bool ok=true;
		for(int i=1;i<=m;i++){
			int dis=abs(a[i].x-a[i-1].x)+abs(a[i].y-a[i-1].y);
			int nt=a[i].t-a[i-1].t;
			if(nt>=dis&&(nt-dis&1)==0)continue;
			ok=false;break;
		}
		if(ok)printf("Yes\n");
		else printf("No\n");
	}
	
	return 0;
}

-T2 西⽐拉先知系统

题面

西⽐拉先知系统是⼀个强⼤的⼼灵指数监测⽹絡,能以声像扫描主动监控市⺠的⼼智与精神状态。为
了判定出更复杂的⼈类⼼理参数,西⽐拉系统纳⼊了不同于既存⼈类规范的超群⼈格──不会随意和他
⼈产⽣共鸣,也不会感情⽤事,能以⾮⼈类的眼光来俯瞰并裁定⼈类。

被纳⼊的超群⼈格会相互影响,共同处理数据。他们之间具体的影响⽅式形如⼀张⽆向图,如果你对
⼀个节点进⾏操作,和这个节点相邻的节点也会受到相同的影响。

操作有⼀种:使⼀个节点的权值加上\(x\)

同时你还希望询问⼀个节点的权值(每⼀个节点的初始权值为0)。

解法

首先,暴力做法很好想,就是对每一个相邻点进行修改。但问题是这个做法可能会被卡,那就是当一个节点的度数很大时,修改的复杂度就会很高。于是考虑对“重点”(度比较多的点)和“轻点”进行分类讨论。

其实理论上来说我的做法也会被卡,但……数据比较水,放了我一马【开心】。

#include<cstdio>
#include<vector>
//#define zczc
using namespace std;
const int N=300010;
const int S=10000;
inline void read(int &wh){
    wh=0;int f=1;char w=getchar();
    while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
    while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar(); }
    wh*=f;return;
}

struct edge{
	int t,next;
}e[N*2];
int esum,head[N];
inline void add(int fr,int to){
	esum++;
	e[esum].t=to;
    e[esum].next=head[fr];
    head[fr]=esum;
}
int m,n,q,d[N];
bool big[N];
vector<int>num[N];//记录每个点相邻的重点 
int a[N],c[N];//加的数和(重点)的实际值 

signed main(){
	
	#ifdef zczc
	freopen("in.txt","r",stdin);
	#endif
	
	int op,s1,s2;
	read(m);read(n);read(q);
	for(int i=1;i<=n;i++){
		read(s1);read(s2);
		add(s1,s2);add(s2,s1);
		d[s1]++,d[s2]++;
	}
	for(int i=1;i<=m;i++)big[i]=d[i]>S;
	for(int i=1;i<=m;i++){
		for(int j=head[i];j;j=e[j].next){
			int th=e[j].t;
			if(big[th])num[i].push_back(th);
		}
	}
	while(q--){
		read(op);
		if(op){
			read(s1);read(s2);
			a[s1]+=s2;
			for(int i=0;i<num[s1].size();i++){
				c[num[s1][i]]+=s2;
			}
		}
		else{
			read(s1);
			if(big[s1])printf("%d\n",a[s1]+c[s1]);
			else{
				int an=a[s1];
				for(int i=head[s1];i;i=e[i].next){
					an+=a[e[i].t];
				}
				printf("%d\n",an);
			}
		}
	}
	
	return 0;
}

-T3 替身使者

题面

众所周知,替⾝使者会互相吸引。

现在有\(n\)个替⾝使者,这些替⾝使者在⼀条很⻓的街道上活动。对于第\(i\)个替⾝使者,他可以在上第\(l_i\)个到第\(r_i\)个商铺中的⼀个停下来休息。

于是,⼀些替⾝使者就会处于同⼀个商铺。对于⼀个商铺,如果有\(x\)个替⾝使者到了这⼀家商铺,那么就会产⽣\(g(x)\)点吸引度,其中\(g(x)\)是⼀个关于\(x\)的多次函数(5次函数,1到5次项的系数输入,其它项为0),求一种使者停留方案使得所有商铺的吸引度最大。

解法

真的没想到竟然是个……区间dp加一点点贪心?满心以为是线性dp的我列了半天方程却然并卵,最后只能贪了15分,可悲啊……

它就是说,如果一个点当前可以有多个区间同时覆盖,那么就贪心地把所有能停留在此的使者全部拿来,再对于这个点左右两个区间进行操作。加上离散化即可。

由于自己太弱,怎么也卡不过最后十分,只好引用一下孙艺恒大佬的代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define int long long
using namespace std;
int n,m,t[7],l[505],r[505],ans=0,vis[505],f[505],dp[505][505],cnt;
struct node
{
	int name,data;
}a[505*2];
int cmp(node fi,node se)
{
	return fi.data<se.data;
}
inline int lowbit(int x)
{
	return -x&x;
}
void update(int x,int k)
{
	while(x<=cnt)
	{
		f[x]+=k;
		x+=lowbit(x);
	}
}
int search(int x)
{
	int num=0;
	while(x)
	{
		num+=f[x];
		x-=lowbit(x);
	}
	return num;
}
int g(int x)
{
	return t[1]*x+t[2]*x*x+t[3]*x*x*x+t[4]*x*x*x*x+t[5]*x*x*x*x*x;
}
signed main()
{
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=5;i++)scanf("%lld",&t[i]);
	for(int i=1;i<=n;i++)
	{
		scanf("%lld%lld",&l[i],&r[i]);
		a[i].name=i,a[i].data=l[i];
		a[i+n].name=i+n,a[i+n].data=r[i];
	}
	sort(a+1,a+1+n*2,cmp);
	a[0].data=-1;
	for(int i=1;i<=n*2;i++)
	{
		if(a[i].data!=a[i-1].data)cnt++;
		if(a[i].name<=n)l[a[i].name]=cnt;
		else r[a[i].name-n]=cnt;
	}
	for(int i=1;i<=n;i++)if(l[i]==r[i])vis[l[i]]++;
	for(int i=1;i<=cnt;i++)dp[i][i]+=g(vis[i]);
	for(int p=2;p<=cnt;p++)
	{
		for(int i=1;i+p-1<=cnt;i++)
		{
			memset(f,0,sizeof(f)); 
			int j=i+p-1;
			for(int k=1;k<=n;k++)
			{
				if(l[k]>=i&&r[k]<=j)update(l[k],1),update(r[k]+1,-1);
			}
			dp[i][j]=max(dp[i][j-1]+g(search(j)),dp[i+1][j]+g(search(i)));
			for(int k=i+1;k<j;k++)
			{
				dp[i][j]=max(dp[i][j],dp[i][k-1]+dp[k+1][j]+g(search(k)));
			}
		}
	}
	printf("%lld",dp[1][cnt]);
	return 0;
}
posted @ 2021-08-25 17:06  Feyn618  阅读(84)  评论(0编辑  收藏  举报