「模拟赛」暑期集训CSP提高模拟2(7.19)

学长组题+预告:题会有点难

雀氏。。。

题目列表

A. 活动投票
B. 序列
C. Legacy
D. DP搬运工1


A.活动投票

题意:

衡中活动很多,人也很多,一次活动有 $n$ 个学生参与投票,现已知一名参赛选手票数超过半数,求其参赛号 $ai$​(参赛号随机,$0≤ai≤21474836470≤ai​≤2147483647)$ 。

很简单吧,重点来了: 时限:0.5s 内存:2M

赛时分析:

这道题难点就在于内存的限制,赛时可能对于计算内存的方法不是很清楚,打了个 \(map数组\) 自己算了算明显会超限制,但不知道自己的计算方法对不对,并且也想不出来别的做法,觉得能拿个五十分吧,就没仔细想跳了。结果实际得分:\(0 pts\),样例是一点分不想让我拿啊。

正解:

记一个 \(now\) 表示现在的数,\(cnt\) 表示现在的数的个数,如果遇到一个新的数 \(x\)\(x=now\),我让 \(cnt\)++,否则 \(cnt\)- -, 当 \(cnt<=0\) 时,\(now=x\), 即将记的数变为现在遇到的数 \(x\)

做法很显然,可以理解为将不同的数消掉,相同的数保留,因为答案的个数大于总个数的一半,那么答案消不完,则最后留下的就是答案。

code:

#include<bits/stdc++.h>
using namespace std;

int n;

int main(){
	// freopen("in.in", "r", stdin); freopen("out.out", "w", stdout);

	scanf("%d", &n);
	int now = 0, cnt = 0;
	for(int i=1; i<=n; i++){
		int x; scanf("%d", &x);	
		if(cnt == 0) {now = x, cnt++; continue;}
		if(x == now) cnt++;
		if(x != now) cnt--;
	}

	cout<<now;

	return 0;
}

其他:

%%%新高一学长神奇做法:把所有元素 mod 几个较小质数(像 7 、13 等),把余数个数记录下,每个模数下最多的余数一定是答案所得,再用 \(CRT\) 就做完了。

B. 序列

C. Legacy

题意:

\(n\) 个点,\(q\) 条边,边有三种:

  1. \(u\) 连点 \(v\),权值为 \(w\)
  2. \(u\) 连向区间 \([l, r]\) 中的所有点,权值为 \(w\)
  3. 区间 \([l, r]\) 连向点 \(u\),权值为 \(w\)

给定 \(s\) 为起始点,求所有点到起始点的最小距离,如果某点到不了起始点则输出 -1。

赛时分析:

题目也没给 \(r-l\) 的取值范围啊,这我也不知道会不会炸啊,虽然挺显然会炸的(没给范围说明 \(r-l\) 可以为最大值 \(n\)),直接打了个暴力,对于有区间的边,循环遍历区间中的点建边,得分:\(20 pts\),其实赛时想到了点线段树和 + \(Dij\) 的,没有继续想,可能因为时间很急(着急打完暴力去打 T2)。

正解:

线段树优化建图板子题,不过没学过。

对于区间的边,把边连在区间包含于所给区间的子树根节点上,然后把子树上的点连通,边权为 0,这样可以保证点可以与区间中的每个实际点连通。

具体实现我们需要建两棵树,第一颗维护树上节点向下(子节点)连边,第二颗相反,维护节点向上(父节点)连边,然后将两棵树相同的叶子节点相连保证两棵树联通。

code:

#include<bits/stdc++.h>
#define lson rt << 1
#define rson rt << 1 | 1
#define ll long long
#define mp make_pair
using namespace std;

const int N = 1e6 + 10;

int n, Q, s, v, wa, op, turn[N], ma;
int tot, head[N], to[N<<3], nxt[N<<3], w[N<<3];
const int D=N>>1;
inline void addedge(int x, int y, int z){
	w[++tot] = z;
	to[tot] = y;
	nxt[tot] = head[x];
	head[x] = tot;
}
namespace Segment_tree
{
	inline void jian(int k,int l,int r){
		if(l==r){
			turn[l]=k;
			return;
		}
		addedge(k,k<<1,0),addedge(k,k<<1|1,0);
		addedge((k<<1)+D,k+D,0),addedge((k<<1|1)+D,k+D,0);
		int mid=l+r>>1;
		jian(k<<1,l,mid),jian(k<<1|1,mid+1,r);
	}
	inline void geng(int k,int l,int r,int L,int R){
		if(L<=l&&r<=R){
			if(op==2)addedge(turn[v],k,wa);
			else addedge(k+D,turn[v],wa);
			return;
		}
		int mid=l+r>>1;
		if(L<=mid)geng(k<<1,l,mid,L,R);
		if(R>mid)geng(k<<1|1,mid+1,r,L,R);
	}
}


ll dis[N]; bool vis[N];
priority_queue<pair<ll, int> >q;

void Dijkstra(int a){
	memset(dis, 0x3f, sizeof(dis));
	memset(vis, 0, sizeof(vis));
	dis[turn[a]] = 0;
	q.push(make_pair(-dis[turn[a]], turn[a]));
	
	while(q.size())
	{
		int x = q.top().second;
		q.pop(); vis[x] = 1;
		// cout<<x<<endl;
		for(int i=head[x]; i; i=nxt[i]){
			int y = to[i];
			// cout<<y<<'K'<<endl;
			if(dis[y] > dis[x] + w[i]){
				dis[y] = dis[x] + w[i];
				if(!vis[y]) q.push(make_pair(-dis[y], y));
			}
		}
	}
}

int main(){
	// freopen("in.in", "r", stdin); freopen("out.out", "w", stdout);
	// cout<<1<<endl;
	scanf("%d%d%d", &n, &Q, &s);

	Segment_tree::jian(1, 1, n);
	// cout<<1<<endl;
	for(int i=1;i<=n;++i)
		addedge(turn[i],turn[i]+D,0),addedge(turn[i]+D,turn[i],0);
	for(int i=1; i<=Q; i++){
		int u, l, r;
		scanf("%d", &op);
		if(op == 1){
			scanf("%d%d%d", &u, &v, &wa);
			addedge(turn[u], turn[v], wa);
		}
		else{
			scanf("%d%d%d%d", &v, &l, &r, &wa);
			Segment_tree::geng(1, 1, n, l, r);
		}
	}
	// cout<<1<<endl;
	Dijkstra(s);

	for(int i=1; i<=n; i++){
		printf("%lld ", dis[turn[i]] == 4557430888798830399 ? -1 : dis[turn[i]]);
	}

	return 0;
}

D. DP搬运工1

posted @ 2024-07-20 10:10  Aqr_Rn  阅读(19)  评论(0编辑  收藏  举报