首页 > 其他分享 >test20221115 打铁记

test20221115 打铁记

时间:2022-11-15 15:14:24浏览次数:39  
标签:10 int test20221115 ret 节点 leq 打铁 复杂度

总述

\(53+20+20+0=93\),班上 \(rk9\),太菜了。

考场 T1 特殊性质+暴力(可是没有打满),T2 特殊性质,T3 暴力。费时 \(40\) 分钟,剩下的时间写正解(没写出来)+摆烂。

感谢 cy 同志让我感受到了被题虐的感觉。

考场解法参见【部分分】部分。

T1. 匹配(2353)

简要题意

令两个区间 \([l,r],[x,y]\) 的节目效果值为:

\[\max_{a=l}^{r}\max_{b=x}^{y}|a-b| \]

有 \(n\) 个区间 \([l_i,r_i]\),你需要对它们两两分组,每组的节目效果值之和最大。输出最这个和。

\(2 \leq n \leq 10^{6},0 \leq l_i \leq r_i \leq 10^9\),保证 \(n\) 为偶数。

部分分

Subtask #1(30pts):\(n\leq 8\),考虑直接暴力 DFS,时间复杂度 \(O(\textbf{玄学})\)。

namespace bf{
	bool vis[1000005];
	int grouped = 0;
	int nowret = 0;
	int result = 0;
	void dfs(){
		if(grouped>=n){
			result=max(result,nowret);
			return;
		}
		for(int i=1;i<=n;i++){
			if(vis[i])continue;
			vis[i]=1;
			for(int j=(i+1);j<=n;j++){
				if(vis[j])continue;
				vis[j]=1;
				grouped += 2;
				nowret += player_group_value(a[i],a[j]);
				dfs();
				grouped -= 2;
				nowret -= player_group_value(a[i],a[j]);
				vis[j]=0;
			}
			vis[i]=0;
		}
	}
	int solve(){
		dfs();
		return result;
	}
}

Subtask #3(20pts):\(l_i=r_i\),直接排序后贪心在左右两端取即可。时间复杂度 \(O(n\log n)\)。

namespace subtask3{
	bool cmp(player x,player y){
		return x.l<y.l;
	}
	int solve(){
		int ret=0;
		sort(a+1,a+n+1,cmp);
		for(int l=1,r=n;l<r;l++,r--){
			ret+=abs(a[l].l-a[r].l);
		}
		return ret;
	}
};

Subtask #4(10pts):\(r_i-l_i=r_j-l_j\),也是排序后贪心取两端。时间复杂度 \(O(n\log n)\)。

namespace subtask4{
	bool cmp(player x,player y){
		return x.l<y.l;
	}
	int solve(){
		int ret=0;
		sort(a+1,a+n+1,cmp);
		for(int l=1,r=n;l<r;l++,r--){
			ret+=player_group_value(a[l],a[r]);
		}
		return ret;
	}
}

正解

考虑一般化。其实我们可以给每一个区间分配一个 \(01\) 属性 \(t\),当 \(t_i=1\) 时取 \(r_i\),否则取 \(-l_i\)。那么我们其实要取 \(\frac{n}{2}\) 个 \(1\) 和 \(0\)。

先将所有的 \(t_i\) 设为 \(1\),将其改为 \(0\),答案需要加上 \(-r_i-l_i\)。将区间按照 \(l_i+r_i\) 排序,贪心改变前 \(\frac{n}{2}\) 个即可。

时间复杂度 \(O(n\log n)\)。本题卡常,需要使用快读。

#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef long long ll;
#define T (1<<15)
char buf[T],*p1=buf,*p2=buf;
#define nc() (p1==p2&&(p2=buf+fread(p1=buf,1,T,stdin),p1==p2)?-1:*p1++)
ll rd(){
	ll x=0;char c;bool s=0;
	do c=nc();while(c!=45&&(c<48||c>57));
	if(c==45)c=nc(),s=1;
	do x=10*x+(c&15),c=nc();while(c>=48&&c<=57);
	return s?-x:x;
}
#undef T
int n;
struct player{
	int l,r;
	bool operator<(const player &x) const {
		return (r+l)<(x.r+x.l);
	}
} p[1000005];

int ret=0;

signed main(){
//	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	freopen("2353.in","r",stdin);
	freopen("2353.out","w",stdout);
	n=rd();
	for(int i=1;i<=n;i++){
		p[i].l=rd();p[i].r=rd();
	}
	sort(p+1,p+n+1);
	for(int i=1;i<=n;i++)ret+=p[i].r;
	for(int i=1;i<=(n>>1);i++)ret=ret-p[i].r-p[i].l;
	printf("%lld",ret);
	return 0;
}

T2. 狼人(2354)

简要题意

给你一个 \(n\) 个节点的树。每一个节点有一个权 \(c_i\) 你需要求出有多少个连通块,使得连通块中权组成的集合存在出现次数大于连通块节点数量的一半的权。答案对 \(998244353\) 取模。

\(1 \leq n \leq 3000,1 \leq c_i \leq n\)

部分分

Subtask #2(20pts):树为 \(1\to 2\to\cdots\to n\) 的链。

链的情况就是连通块为区间,这道题就变成了给你一个序列求有多少个子区间的众数出现次数大于区间长度的一半。直接枚举区间用 std::map 维护众数即可。

时间复杂度 \(O(n^2\log n)\),可以卡过。

int mm[3005];
int c[3005];
int ret=0;
for(int i=1;i<=n;i++){
	memset(mm,0,sizeof(mm));
	int zs=0;
	for(int j=i;j<=n;j++){
		mm[c[j]]++;
		if(mm[zs]<mm[c[j]]){
			zs=c[j];
		}
		if((2*mm[zs])>(j-i+1)){
			ret++;
		}
	}
}
cout<<ret;

T3. 旅行(2355)

简要题意

有 \(n\) 个节点,对于任意的 \(i(1 \leq i \leq n-1)\),有有向边 \((i,i+1),(i,i+2),\cdots,(i,i+T_i-1),(i,i+T_i)\)。(显然图为一个 DAG)

给定正整数 \(K\) 和自然数 \(D\),如果沿着边 \((i,j)\) 从 \(i\) 到 \(j\),需要花费代价为:

\[C_{i,j}=\lfloor \frac{j-i}{K} \rfloor \cdot D \]

另外,每一个节点有一个权值 \(H_i\)。定义一条路径 \(P_1 \to P_2\to \cdots \to P_{m-1}\to P_m\),那么这条路径的快乐程度为:

\[\sum_{i=1}^{n}{H_{P_i}}-\sum_{i=1}^{n-1}{C_{P_i,P_{i+1}}} \]

即经过节点的权值总和与总花费的差。

定义 \(f_i\) 为从 \(i\) 出发到 \(n\) 的最大快乐程度。输出:

\[\operatorname{xor}\limits_{i=1}^{n}{f_i+i} \]

\(1 \leq K \leq n \leq 2 \times 10^{6},0 \leq D,|H_i| \leq 10^{10},1 \leq T_i \leq n-i\)。

部分分

Subtask #1(20pts):\(n \leq 3000\),可以考虑暴力建出反图后从 \(n\) 开始 DP,每一个节点需要等到其入节点遍历完后开始遍历。则易得状态转移方程:

\[f_v=\max_{(u,v)\in\operatorname{Graph}}{f_u+H_v-\lfloor\frac{u-v}{K}\rfloor\cdot D} \]

初始条件 \(f_n=H_n\)。

也可以在拓扑序上 DP,原理相同(想一想为什么)。

时间复杂度瓶颈在建图,时间复杂度为 \(O(n(\sum_{i=1}^{n-1}{T_i}))\)。

int n,k,d;
int cnt[N],in[N],f[N];
int h[N];

void dfs(int u){
	for(int i=head[u];i;i=g[i].nxt){
		int v=g[i].to;
		cnt[v]++;
		f[v]=max(f[v],f[u]+h[v]-((u-v)/k)*d);
		if(cnt[v]>=in[v]){
			dfs(v);
		}
	}
}

signed main(){
	freopen("2355.in","r",stdin);
	freopen("2355.out","w",stdout);
	memset(f,0x8f,sizeof(f));
	n=rd();k=rd();d=rd();
	for(int i=1;i<=n;i++){
		h[i]=rd();
	}
	for(int i=1,t;i<n;i++){
		t=rd();
		for(int j=(i+1);j<=(i+t);j++){
			add(j,i);
			in[i]++;
		}
	}
	f[n]=h[n];
	dfs(n);
	int result=0;
	for(int i=1;i<=n;i++){
		result^=(f[i]+i);
	}
	printf("%lld",result);
	return 0;
}

标签:10,int,test20221115,ret,节点,leq,打铁,复杂度
From: https://www.cnblogs.com/zheyuanxie/p/test20221115.html

相关文章

  • 趁热打铁!一起来看下Airtest1.2.7新增的那些断言API
    1.前言先前我们放出了1.2.7版本的Airtest,其中,一个很重要的功能是,我们新增了非常丰富的断言API,今天我们就来详细看一下新版Airtest都有给我们提供哪些断言语句。2.旧......
  • NOI2022打铁记
    不建议使用Ctrl+A阅读。Day-7CCF不讲武德,让提前一周到,于是坐上了去南京的飞机。早餐的萝卜条应该是配面包一块吃的,我硬是分开吃完了(在飞机上和学长坐在同一排,中间......