ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

9.19 考试总结

2020-09-21 08:03:13  阅读:195  来源: 互联网

标签:总结 ch 测试点 9.19 int memset leq include 考试


前言:

貌似自己的开题和别人好像不太一样,别人都是 \(T1-T2-T3\) ,好像没几个像我一样 \(T3-T2-T1\) 的。大雾

T1 潜伏

题目描述:

⼩悠回家之后,跟着⺟亲看了很多抗⽇神剧,其中不乏⼀些谍战⽚。

解放前夕,北平城内潜伏着若⼲名地下党员,他们居住在城市的不同位置。现在身为地下党第⼀指挥官
的你,想知道地下党员之间的最⼩通信距离,即从某⼀地下党员住处前往另⼀地下党员住处的距离的最
⼩值。
我们可以将北平城视为⼀张 \(N\) 个点 \(M\) 条边的⽆向图,每条边连接两个点 \(u_i,v_i\),且长度为 \(w_i\)。

输入格式:

每个测试点包含多组数据。

第⼀⾏,给出数据组数 \(T\),之后依次输⼊每组数据。

每组数据的第⼀⾏ \(N\),\(M\) , \(K\) 分别表示点数,边数,地下党员数。

之后 \(M\) ⾏,每⾏ \(u_i,v_i,w_i\) 表示第 \(i\) 条边。

之后⼀⾏,\(k\) 个整数代表地下党员所在结点。

结点编号为 \(1\) 到 \(N\),保证 \(0 \leq k \leq N\)。

输出格式:

对于每组数据,输出⼀⾏⼀个整数,表示地下党员之间的最⼩通信距离。

如果最⼩通信距离为 \(\infty\),请输出 \(-1\) 代替

说明与提示:

对于所有测试点 \(T\leq 100\)。

对于 \(50%\) 的测试点 \(N\leq 1000\),\(M\leq 2000\) 。

对于 \(20%\) 的测试点 \(N\leq 100000\),输⼊的⽆向图⽆环。

对于30%的测试点 \(N\leq 100000\),\(m\leq 200000\) 。

所有 \(0\leq w_i\leq 1000\) 。

一个比较裸的多源最短路问题,但我当时没想出来用二进制来压缩状态,直接就GG了。

只能打个 \(50pts\) 暴力滚粗。

50pts Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
#define int long long
const int N = 1e5+10;
int T,n,m,k,u,v,w,ans,tot;
int head[N],dis[N],c[N];
bool vis[N];
struct node
{
	int to,net,w;
}e[N<<1];
inline int read()
{
	int s = 0,w = 1; char ch = getchar();
	while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
	return s * w;
}
void add(int x,int y,int w)
{
	e[++tot].to = y;
	e[tot].w = w;
	e[tot].net = head[x];
	head[x] = tot;
}
void spfa(int x)
{
	priority_queue<pair<int,int> > q;
	memset(dis,0x3f,sizeof(dis));
	memset(vis,0,sizeof(vis));
	q.push(make_pair(0,x)); dis[x] = 0; 
	while(!q.empty())
	{
		int t = q.top().second; q.pop();
		if(vis[t]) continue; 
		vis[t] = 1;
		for(int i = head[t]; i; i = e[i].net)
		{
			int to = e[i].to;
			if(dis[to] > dis[t] + e[i].w)
			{
				dis[to] = dis[t] + e[i].w;
				q.push(make_pair(-dis[to],to));
			} 
		}
	}
}
void qingkong()
{
	tot = 0;
	memset(head,0,sizeof(head));
	memset(dis,0,sizeof(dis));
	memset(vis,0,sizeof(vis));
	memset(c,0,sizeof(c));
}
signed main()
{
	// freopen("hide.in","r",stdin);
	// freopen("hide.out","w",stdout);
	T = read();
	while(T--)
	{
		qingkong();
		n = read(); m = read(); k = read(); ans = 1e15;
		for(int i = 1; i <= m; i++)
		{
			u = read(); v = read(); w = read();
			add(u,v,w); add(v,u,w);
		}
		for(int i = 1; i <= k; i++) c[i] = read();
		for(int i = 1; i <= k; i++)
		{
			spfa(c[i]);
			for(int j = i+1; j <= k; j++) 
			{
				ans = min(ans,dis[c[j]]);
			}
		}
		if(ans == 1e15) printf("%lld\n",-1);
		else printf("%lld\n",ans);
	}
	fclose(stdin); fclose(stdout);
	return 0;
}

T2 神经

题目描述:

神经⽹络可以表示为 \(N\) 个点 \(M\) 条边的有向图,每个结点带有⼀个兴奋权值 \(w_i\)。

如果以 \(x\) 单位⼤⼩的电流刺激结点 ,设 \(v_1,v_2,.....v_k\) 是从 \(x\) 出发可以到达的结点,

则神经⽹络会产⽣ \(x\times max(w_{v_1},w_{v_2}.....w_{v_k})\)的兴奋度,请注意,我们认为从 \(u\) 出发可以到达 \(u\) 。

现在请你回答若⼲询问,每个询问表示为:在以 \(x\) ⼤⼩的电流刺激 \(u\) 点后,⽹络的兴奋度是多少。

输入格式:

每个测试点包含多组数据。

第⼀⾏,⼀个整数 \(T\) 表示数据组数,之后依次输⼊每组数据。

每组数据第⼀⾏, \(N,M,K\) 分别表示点数,边数,询问次数。

之后⼀⾏, \(N\) 个整数, \(w_1,w_2,.....w_N\)表示每个点的兴奋权值。

之后 \(M\) ⾏,每⾏ \(u_iv_i\) 表示⼀条从 \(u_i\) 到 \(v_i\) 的单向边。

之后 \(k\) ⾏,每⾏ \(u,x\) 表示⼀次刺激。

输出格式:

对于每个测试点中的每个询问,输出⼀⾏⼀个整数表示答案。

数据范围与提示:

对于所有数据, \(T\leq 5\)

对于50%的测试点, \(N\leq100,M\leq 2000,K\leq 1000\)。

对于20%的测试点, \(N\leq 100000,M\leq 200000,K\leq 100000\),输⼊的有向图构成DAG。

对于30%的测试点 \(N\leq 200000,M\leq 400000,K\leq 100000\)。

所有 \(0\leq x,w_i\leq 10^9\)。

这道题在数据范围的时候已经给出做法了,输入保证有向图构成 \(DAG\) 直接对整张图跑一边 拓扑排序加 \(dp\) 就可以解决。

但数据没有保证不存在环,所以我们需要对整张图缩一下点,然后对每个强连通分量再跑拓扑排序。

另外一种写法就是对整张图跑 \(dij\) 进行松弛操作,那种写法实现起来要比这个好写点。

Code:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
#define int long long
const int N = 2e5+10;
int T,n,m,k,u,o,x,num,top,cnt,tot;
int dfn[N],low[N],head[N],shu[N],w[N],f[N],du[N],sta[N];
bool vis[N];
vector<int> v[N];
inline int read()
{
	int s = 0,w = 1; char ch = getchar();
	while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
	return s * w;
}
struct node
{
	int to,net;
}e[N<<1];
void add(int x,int y)
{
	e[++tot].to = y;
	e[tot].net = head[x];
	head[x] = tot;
}
void tarjain(int x)//缩点
{
	dfn[x] = low[x] = ++num;
	sta[++top] = x; vis[x] = 1;
	for(int i = head[x]; i; i = e[i].net)
	{
		int to = e[i].to;
		if(!dfn[to])
		{
			tarjain(to);
			low[x] = min(low[x],low[to]);
		}
		else if(vis[to])
		{
			low[x] = min(low[x],dfn[to]);
		}
	} 
	if(dfn[x] == low[x])
	{
		cnt++; int y;
		do
		{
			y = sta[top--];
			shu[y] = cnt;
			f[cnt] = max(f[cnt],w[y]);
			vis[y] = 0;
		}while(x != y);
	}
}
void rebuild()
{
	for(int i = 1; i <= n; i++)
	{
		for(int j = head[i]; j; j = e[j].net)
		{
			int to = e[j].to;
			if(shu[i] != shu[to])
			{
				v[shu[to]].push_back(shu[i]);
				du[shu[i]]++;
			}
		}
	}
}
void tupo()//拓扑排序加dp
{
	queue<int> q;
	for(int i = 1; i <= cnt; i++)
	{
		if(du[i] == 0) q.push(i);
	}
	while(!q.empty())
	{
		int t = q.front(); q.pop();
		for(int j = 0; j < (int) v[t].size(); j++)
		{
			int to = v[t][j];
//			cout<<to<<" "<<t<<endl;
			f[to] = max(f[to],f[t]);
			if(--du[to] == 0) 
			{
				q.push(to);
			}
		}
	}
}
void qingkong()
{
	tot = num = cnt = top = 0;
	memset(head,0,sizeof(head));
	memset(dfn,0,sizeof(dfn));
	memset(low,0,sizeof(low));
	memset(f,0,sizeof(f));
	memset(vis,0,sizeof(vis));
	memset(du,0,sizeof(du));
	memset(w,0,sizeof(w));
	memset(shu,0,sizeof(shu));
	for(int i = 1; i <= n; i++) v[i].clear();
}
signed main()
{
	// freopen("neural.in","r",stdin);
	// freopen("neural.out","w",stdout);
	T = read();
	while(T--)
	{
		qingkong();
		n = read(); m = read(); k = read();
		for(int i = 1; i <= n; i++) w[i] = read();
		for(int i = 1; i <= m; i++)
		{
			u = read(); o = read();
			add(u,o);
		}
		for(int i = 1; i <= n; i++) //缩点
		{
			if(!dfn[i]) tarjain(i);
		}	
		rebuild(); tupo();//重新建图加拓扑排序
		for(int i = 1; i <= k; i++)
		{
			u = read(); x = read();
			printf("%lld\n",x * f[shu[u]]);
		}
	}
	fclose(stdin); fclose(stdout);
	return 0;
}

T3计树

题目描述:

小悠的导师对于树叶颜⾊有很深的研究,但是碍于眼神不好,总是要请⼩悠来帮忙数⼀数树上某种颜⾊的叶⼦有多少⽚。

给出一棵 \(N\) 个结点的树,每个结点初始具有⼀个颜⾊ ,现在有如下两种操作——

  1. 更改结点 \(u\) 的颜⾊为 \(x\) 。
  2. 询问从 \(u\) 到 \(v\) 的路径上有多少个颜⾊为 \(x\) 的结点。

现在请你按顺序完成若⼲次操作。

输入格式:

每个测试点包含多组数据。

第 \(1\),个整数 表示数据组数 \(T\),之后依次输⼊每组数据。

每组数据第 \(N\),\(M\) 分别表示点数、操作次数。
之后 \(N\) 个整数 表示每个点的初始颜⾊。
之后 \(n-1\) ,每⾏两个整数 \(u\),\(v\) ,表示树上存在⼀条连接 的边。
之后 \(m\) ,表示每个操作。
如果是操作 \(1\),则形如 \(1,u,x\)。
如果是操作 \(2\),则形如 \(1,u,v,x\)。

输出格式:

对于每组数据的每个操作2,输出⼀⾏⼀个整数表示答案。

数据范围与提示:

对于所有测试点 \(T \leq 5\)。

对于50%的测试点 \(N\leq 1000\),\(M\leq 1000\) 。

对于20%的测试点 \(N\leq 100000\),\(M\leq 100000\) ,颜⾊种类数不超过5。

对于30%的测试点 \(N\leq 100000\),\(M\leq 100000\) 。

所有测试点颜⾊种类数均不超过 \(100\) 。

一开始我想这不就是把数颜色那道题套的树上了吗?直接上树上带修莫队,然鹅自己并不会写。

看了一眼数据范围才发现,这道题是个树剖套线段树的裸题,直接对每个颜色开个线段树来维护就好了。

三十分钟码完,结果debug 用了一个小时。

为了卡一下时间,我还特意把建树过程省了。结果在 \(lemon\) 上测还是 \(TLE\) ,但在 \(oj\) 上就测得没问题,1e5的数据完全可以跑过去。

\(lemon\) 差评,大雾

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 1e5+10;
int n,m,u,v,x,tot,num,T,opt;
int head[N],dep[N],dfn[N],siz[N],son[N],fa[N],top[N];
int tr[110][N<<2],col[N];
struct node
{
	int to,net;
}e[N<<1];
inline int read()
{
	int s = 0,w = 1; char ch = getchar();
	while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
	return s * w;
}
void add(int x,int y)
{
	e[++tot].to = y;
	e[tot].net = head[x];
	head[x] = tot;
}
void get_tree(int x)
{
	dep[x] = dep[fa[x]] + 1; siz[x] = 1;
	for(int i = head[x]; i; i = e[i].net)
	{
		int to = e[i].to;
		if(to == fa[x]) continue;
		fa[to] = x;
		get_tree(to);
		siz[x] += siz[to];
		if(siz[to] > siz[son[x]]) son[x] = to; 
	}
}
void dfs(int x,int topp)
{
	top[x] = topp; dfn[x] = ++num; 
	if(son[x]) dfs(son[x],topp);
	for(int i = head[x]; i; i = e[i].net)
	{
		int to = e[i].to;
		if(to == fa[x] || to == son[x]) continue;
		dfs(to,to);
	}
}
void up(int now,int o)
{
	tr[now][o] = tr[now][o<<1] + tr[now][o<<1|1];
}
void chenge(int now,int o,int L,int R,int x,int val)
{
	if(L == R)
	{
		tr[now][o] += val;
		return;
	}
	int mid = (L + R)>>1;
	if(x <= mid) chenge(now,o<<1,L,mid,x,val);
	if(x > mid) chenge(now,o<<1|1,mid+1,R,x,val);
	up(now,o);
}
int query(int now,int o,int L,int R,int ql,int qr)
{
	int res = 0;
	if(ql <= L && qr >= R) return tr[now][o];
	int mid = (L + R)>>1;
	if(ql <= mid) res += query(now,o<<1,L,mid,ql,qr);
	if(qr > mid) res += query(now,o<<1|1,mid+1,R,ql,qr);
	return res;
}
int ask(int x,int y,int now)
{
	int res = 0;
	while(top[x] != top[y])
	{
		if(dep[top[x]] < dep[top[y]]) swap(x,y);
		res += query(now,1,1,n,dfn[top[x]],dfn[x]);
		x = fa[top[x]];
	}
	if(dep[x] >= dep[y]) swap(x,y);
	res += query(now,1,1,n,dfn[x],dfn[y]);
	return res;
}
void qingkong()
{
	tot = num = 0;
	memset(col,0,sizeof(col));
	memset(head,0,sizeof(head));
	memset(dfn,0,sizeof(dfn));
	memset(tr,0,sizeof(tr));
	memset(dep,0,sizeof(dep));
	memset(fa,0,sizeof(fa));
	memset(siz,0,sizeof(siz));
	memset(son,0,sizeof(son));
	memset(top,0,sizeof(top));
}
int main()
{
//	freopen("count.in","r",stdin);
//	freopen("count.out","w",stdout);
	T = read();
	while(T--)
	{
		qingkong();
		n = read(); m = read();
		for(int i = 1; i <= n; i++) col[i] = read();
		for(int i = 1; i <= n-1; i++)
		{
			u = read(); v = read();
			add(u,v); add(v,u);
		}
		get_tree(1); dfs(1,1);
		for(int i = 1; i <= n; i++)
		{
			chenge(col[i],1,1,n,dfn[i],1);
		}
		for(int i = 1; i <= m; i++)
		{
			opt = read();
			if(opt == 1)
			{
				u = read(); x = read();
				chenge(col[u],1,1,n,dfn[u],-1);
				chenge(x,1,1,n,dfn[u],1);
				col[u] = x;
			}
			else if(opt == 2)
			{
				u = read(); v = read(); x = read();
				printf("%d\n",ask(u,v,x));
			}
		}
	}
	fclose(stdin); fclose(stdout);
	return 0;
}

口胡一下正解的写法吧,我们可以对于每个颜色都开个 \(vector\) 存涉及到这个颜色的操作,也就是把颜色离线下来,之后再枚举每个颜色,统计每个询问的答案就

可以,复杂度貌似是 \(clog^2n\) 的,跑的飞快 \(300ms\) 都可以跑过去。

总结

期望得分:50+100+100 = 250

实际上因为 \(lemon\) 的一些问题,直接炸成 \(50+100+70 = 220\) ,芜湖原地起飞、

感觉这套题的思维难度不是很大,但代码难度的话却不一样了,写完了 \(debug\) 就需要好几个小时。

这难道就是所谓的 码农局,大雾

另外,每题都是多组数据,每次都要注意清空,好烦。

标签:总结,ch,测试点,9.19,int,memset,leq,include,考试
来源: https://www.cnblogs.com/genshy/p/13703569.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有