暑假集训3

去年暑假打过一次,但是当时太菜,今天看到之前写过,好奇多少分,考后交了一发,发现自己是真的菜

然后,就算开了个坑吧,四道题。。。

A. 数列

\(exgcd\)板子

然后,\(exgcd\)咋用来着?

滚回去学数论基础了

code
#include <cstdio>
using namespace std;
#define int long long
int min(int x, int y) { return x < y ? x : y; }
int max(int x, int y){return x > y ? x : y;}
int abs(int x) { return x < 0 ? -x : x; }
void swap(int &x, int &y){x ^= y; y ^= x; x ^= y;}
int exgcd(int a, int b, int &x, int &y){
	if(b == 0){
		x = 1; y = 0;
		return a;
	}
	int gcd = exgcd(b, a % b, y, x);
	y = y - a / b * x;
	return gcd;
}
signed main(){
	int n, a, b;
	scanf("%lld%lld%lld", &n, &a, &b);
	int x, y; if(a > b)swap(a, b);
	int gcd = exgcd(a, b, x, y);
	b = b / gcd; a = a / gcd;
	x = (x % b + b) % b;
	int ans = 0;
	bool flag = 1;
	for (int i = 1; i <= n; ++i){
		int now; scanf("%lld",&now); now = abs(now);
		if(now % gcd)flag = 0;
		if(flag){
			now = now / gcd;
			int nx = (x * now % b + b) % b;
			int ny = (now - a * nx) / b;
			ans += min(abs(nx) + abs(ny), abs(nx - b) + abs(ny + a));
		}
	}
	if(flag)printf("%lld\n", ans);
	else printf("-1\n");
	return 0;
}

B.数对

$a_i >b_j $ 且 $ b_i > a_j $

\(a_i + b_i >a_j + b_j\)

所以按照\(a+b\)排序,然后线段树优化

\(a+b\)相同的\(a\)小的在前

code
#include<bits/stdc++.h>

using namespace std;

const int maxn = 200005;
typedef long long ll;
int n;
struct note{
	ll a, b, w;
	bool operator < (const note & x)const{
		return a + b == x.a + x.b ? a < x.a : a + b < x.a + x.b;
	}
}d[maxn];
struct tree{
	ll t[maxn << 2 | 1], add[maxn << 2 | 1];
	void push_up(int x){t[x] = max(t[x << 1], t[x << 1 | 1]);}
	void push_down(int x){
		int ls = x << 1, rs = x << 1 | 1;
		t[ls] +=  add[x];
		t[rs] +=  add[x];
		add[ls] += add[x];
		add[rs] += add[x];
		add[x] = 0;
	}
	void modify(int x, int l, int r, int pos, ll val){
		if(l == r)return t[x] = max(val, t[x]), void();
		int mid = (l + r) >> 1;
		if(add[x])push_down(x);
		if(pos <= mid)modify(x << 1, l, mid, pos, val);
		else modify(x << 1 | 1, mid + 1, r, pos, val);
		push_up(x);
	}
	void modify_add(int x, int l, int r, int L, int R, ll val){
		if(L <= l && r <= R){
			t[x] += val;
			add[x] += val;
			return;
		}
		if(add[x])push_down(x);
		int mid = (l + r) >> 1;
		if(L <= mid)modify_add(x << 1, l, mid, L, R, val);
		if(R > mid)modify_add(x << 1 | 1, mid + 1, r, L, R, val);
		push_up(x);
	}
	ll query(int x, int l, int r, int L, int R){
		if(L <= l && r <= R)return t[x];
		int mid = (l + r) >> 1;
		if(add[x])push_down(x);
		ll ans = 0;
		if(L <= mid)ans = max(ans, query(x << 1, l, mid, L, R));
		if(R > mid)ans = max(ans, query(x << 1 | 1, mid + 1, r, L, R));
		return ans;
	}
}t;
int lsh[maxn << 1 | 1], cnt;
int main(){
	scanf("%d",&n);
	for(int i = 1; i <= n; ++i)scanf("%lld%lld%lld",&d[i].a, &d[i].b, &d[i].w);
	for(int i = 1; i <= n; ++i)lsh[++cnt] = d[i].a, lsh[++cnt] = d[i].b;
	sort(lsh + 1, lsh + cnt + 1); cnt = unique(lsh + 1, lsh + cnt + 1) - lsh - 1;
	for(int i = 1; i <= n; ++i)d[i].a = lower_bound(lsh + 1, lsh + cnt + 1, d[i].a) - lsh;
	for(int i = 1; i <= n; ++i)d[i].b = lower_bound(lsh + 1, lsh + cnt + 1, d[i].b) - lsh;
	sort(d + 1, d + n + 1);
	for(int i = 1; i <= n; ++i){
		if(d[i].a < d[i].b)t.modify_add(1, 1, cnt, d[i].a + 1, d[i].b, d[i].w);
		t.modify(1, 1, cnt, d[i].a, d[i].w + t.query(1, 1, cnt, 1, min(d[i].a, d[i].b)));
	}
	printf("%lld\n",t.query(1, 1, cnt, 1, cnt));
	return 0;
}

C. 最小距离

多源最短路,记录由哪个特殊点更新,枚举边更新链接的两个点的记录的特殊点的答案

code
#include<bits/stdc++.h>

using namespace std;

const int maxn = 200005;
typedef long long ll;
typedef pair<ll, int> pli;
struct edge{int to, net, val;}e[maxn << 3 | 1];
int tot, head[maxn];
void add(int u, int v, int w){
	e[++tot].net = head[u];
	head[u] = tot;
	e[tot].to = v;
	e[tot].val = w;
}
ll dis[maxn],ans[maxn];
bool vis[maxn];
int n, m, p, rem[maxn], ts[maxn];
priority_queue<pli, vector<pli>, greater<pli> >q;
int main(){
	scanf("%d%d%d", &n, &m, &p);
	for (int i = 1; i <= p; ++i) scanf("%d", &ts[i]);
	for (int i = 1; i <= m; ++i){
		int u, v, w;
		scanf("%d%d%d", &u, &v, &w);
		add(u, v, w); add(v, u, w);
	}
	memset(ans, 0x3f, sizeof(ans));
	memset(dis, 0x3f, sizeof(dis));
	for(int i = 1; i <= p; ++i)	q.push(pli(0, ts[i])), dis[ts[i]] = 0, rem[ts[i]] = ts[i];
	while(!q.empty()){
		int x = q.top().second; q.pop();
		if(vis[x])continue; vis[x] = 1;
		for(int i = head[x]; i; i = e[i].net){
			int v = e[i].to;
			if(dis[v] > dis[x] + e[i].val){
				dis[v] = dis[x] + e[i].val;
				rem[v] = rem[x];
				q.push(pli(dis[v], v));
			}
		}
	}
	// for(int i = 1; i <= n; ++i)printf("%d ",dis[i]);
	for(int i = 1; i <= m; ++i){
		int u = e[i + i].to, v = e[i + i - 1].to;
		// printf("%d %d %d %d\n",u, v, rem[u], rem[v]);
		if(rem[u] != rem[v]){
			ll d = dis[u] + dis[v] + e[i + i].val;
			ans[rem[u]] = min(ans[rem[u]], d);
			ans[rem[v]] = min(ans[rem[v]], d);
		}
	}
	for(int i = 1; i <= p; ++i)printf("%lld ", ans[ts[i]]);
	return 0;
}

D.真相

感谢\(KafuuChinocpp\)题解

考虑某人说\(+、-\)那么他后面的人说话的真假就确定了,所以没有\(\S\)可以直接扫一遍看是否矛盾

\(\$\)的,如果他的真假性确定,那么前面有多少人说真话/假话就确定了,开桶维护有\(i\)个人说真话的断言为真时有多少人说真话,使用差分进行优化

code
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>

using namespace std;

const int maxn = 1e5 + 55;
int tot, n;
char c[maxn];
int num[maxn];

void check(){
	bool flag = true;
	for(int i = 1; i <= n; ++i)if(c[i] == '-')flag = 1 - flag;
	if(flag){printf("consistent\n");return;}
	flag = false;
	for(int i = 1; i <= n; ++i)if(c[i] == '-')flag = 1 - flag;
	if(!flag){printf("consistent\n");return;}
	printf("inconsistent\n");return;
}
int cf[maxn], sum[maxn];
int las(int x){return x == 1 ? n : x - 1;}
void work(){
	for(int i = 0; i <= n; ++i)cf[i] = 0;
	for(int i = 0; i <= n; ++i)sum[i] = 0;
	int l, r;
	for(int i = 1; i <= n; ++i)if(c[i] == '$'){l = r = i; break;}
	do{
		int pos = l;
		int ctrue = 1, cfalse = 0; bool now = 1;
		while(c[las(l)] != '$'){
			l = las(l);
			if(c[l] == '-')now = 1 - now;
			ctrue += now; cfalse += 1 - now;
		}
		sum[num[pos]] += ctrue;
		cf[0] += cfalse;
		cf[num[pos]] -= cfalse;
		cf[num[pos] + 1] += cfalse;
		l = las(l);
	}while(l != r);
	sum[0] += cf[0];
	for(int i = 1; i <= n; ++i){
		cf[i] += cf[i - 1];
		sum[i] += cf[i];
	}
    for(int i = 0; i <= n; ++i)if(sum[i] == i){printf("consistent\n");return;}
    printf("inconsistent\n");
}

int main(){
	int t; scanf("%d",&t);
	for(int ask = 1; ask <= t; ++ask){
		tot = 0; scanf("%d",&n);
		for(int i = 1; i <= n; ++i){
			scanf(" %c",&c[i]);
			if(c[i] == '$')++tot, scanf("%d",&num[i]);
		}
		if(tot)work();
		else check();
	}
	return 0;
}
posted @ 2022-08-15 21:14  Chen_jr  阅读(31)  评论(0编辑  收藏  举报