Winter Training Test1

D - Directing Edges

 CodeForces - 1385E 

题目大意:给定一张图,一些有向边,一些无向边,问是否存在一种方案,对所有的无向边确定方向后不存在环,输出方案

对于不存在方案的情况,即一条边无论选择任意方向都不满足条件,即对于任意方向都成环,即原图有环

所以只建立有向边,进行拓扑,有环就无解

考虑如何输出方案

拓扑排序的时候保存出队的时候的顺序,对于一条有向边,总是先出指向后出,因此对于其他的边,也进行相同的操作,先出指向后出

#include<iostream>
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
#define db double
using namespace std;

int read() {
	int rt = 0, f = 1;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		if (ch == '-') f = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <='9') {
		rt = (rt << 3) + (rt << 1) + ch - '0';
		ch = getchar();
	}
	return rt * f;
}

const int maxn = 2e5 + 5;
int n, m, T;

struct Edge {
	int nxt, to;
}e[maxn << 1];
int h[maxn], tot, rk[maxn], dgr[maxn], cnt, ton[maxn];
struct e {
	int u, v, t;
}E[maxn];

void init() {
	for (int i = 1; i <= n; i++) h[i] = 0, dgr[i] = 0;
	tot = 0;
	cnt = 0;
}

void add(int u, int v) {
	tot++;
	e[tot].to = v;
	e[tot].nxt = h[u];
	h[u] = tot;
}


queue<int> q;

void topsort() {
	while (!q.empty()) {
		int u = q.front();
		q.pop();
		ton[++cnt] = u;
		for (int i = h[u]; i; i = e[i].nxt) {
			int v = e[i].to;
			dgr[v]--;
			if (!dgr[v]) q.push(v);
		}
	}
}

int main() {
	T = read();
	while (T--) {
		n = read(), m = read();
		init();
		for (int i = 1; i <= m; i++) {
			E[i].t = read();
			E[i].u = read();
			E[i].v = read();
			if (E[i].t == 1) {
				add(E[i].u, E[i].v);
				dgr[E[i].v]++;
			}
		}
		cnt = 0;
		for (int i = 1; i <= n; i++) {
			if (!dgr[i]) q.push(i);
		}
		topsort();
		if (cnt < n) {
			puts("NO");
			continue;
		} 
		puts("YES");
		for (int i = 1; i <= cnt; i++) {
			rk[ton[i]] = i;
		}
		for (int i = 1; i <= m; i++) {
			if (rk[E[i].u] < rk[E[i].v]) {
				printf("%d %d\n", E[i].u, E[i].v);
			} else {
				printf("%d %d\n", E[i].v, E[i].u);
			}
		}
	}
	return 0;
}
/*
4
3 1
0 1 3
5 5
0 2 1
1 1 5
1 5 4
0 5 2
1 3 5
4 5
1 1 2
0 4 3
1 3 1
0 2 3
1 2 4
4 5
1 4 1
1 1 3
0 1 2
1 2 4
1 3 2
*/

E - Weighting a Tree

 CodeForces - 901D

题目大意:

给定一张图,给出每个点的一个权值,要求找出一种构造方案,对于每个点,所有边权之和等于这个点的权值

对于一个点及其所有边的情况,考虑生成树之后再调整

对于一棵树,叶子节点只有一条边,边权一定,向上一直更新到根

对于根,如果此时和为给定值,即成立,不为给定值时,就要找到一条非树边,去调整权值

一条非树边有两种情况,成奇环或成偶环

偶环改变权值对根无影响,奇环造成两倍绝对值的影响,所以只需要找到一个奇环,改2倍权值并改变LCA中间的所有边权

代码待填 

F - Sasha and Array

 CodeForces - 718C 

题目大意:

给定一个初始序列,有两个操作

1.区间加x

2.求区间f(x)的和 f(x)为斐波那契数列第x项

考试忘了矩阵分配律

斐波那契数列有矩阵加速的求法

1 1

1 0 

左乘该矩阵即得到下一项

区间加x就是乘这个矩阵的x次幂

线段树维护矩阵就好了

结构体内部初值不为0!

#include<iostream>
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
#define db double
using namespace std;

ll read() {
	ll rt = 0, f = 1;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		if (ch == '-') f = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <='9') {
		rt = (rt << 3) + (rt << 1) + ch - '0';
		ch = getchar();
	}
	return rt * f;
}
const int maxn = 1e5 + 5;
const int Mod = 1e9 + 7;

int n, m;
ll a[maxn];

struct Mat {
	ll a[3][3];
}f[maxn << 2], tag[maxn << 2], s;
bool flag[maxn << 2];

Mat newnode() {
	Mat rt;
	for (int i = 1; i <= 2; i++) {
		for (int j = 1; j <= 2; j++) rt.a[i][j] = 0;
	}
	return rt;
}

Mat add(Mat x, Mat y) {
	Mat rt;
	for (int i = 1; i <= 2; i++) {
		for (int j = 1; j <= 2; j++) {
			rt.a[i][j] = x.a[i][j] + y.a[i][j];
			if (rt.a[i][j] >= Mod) rt.a[i][j] -= Mod;
		}
	}
	return rt;
}

Mat mul(Mat x, Mat y) {
	Mat rt = newnode();
	for (int i = 1; i <= 2; i++) {
		for (int j = 1; j <= 2; j++) {
			for (int k = 1; k <= 2; k++) {
				rt.a[i][j] += x.a[i][k] * y.a[k][j] % Mod;
				rt.a[i][j] %= Mod;
			}
		}
	}
	return rt;
}

Mat mpow(Mat x, ll b) {
	Mat rt = newnode();
	if (b == -1) {
		rt.a[1][2] = 1;
		rt.a[2][1] = 1;
		rt.a[2][2] = -1;
		return rt;
	}
	for (int i = 1; i <= 2; i++) rt.a[i][i] = 1;
	while (b) {
		if (b & 1) rt = mul(rt, x);
		b >>= 1;
		x = mul(x, x);
	}
	return rt;
}

void update(int o) {
	f[o] = add(f[o << 1], f[o << 1 | 1]);
}

void build(int o, int lf, int rg) {
	tag[o] = newnode();
	tag[o].a[1][1] = tag[o].a[2][2] = 1;
	flag[o] = 0;
	if (lf == rg) {
		f[o] = mpow(s, a[lf] - 2);
		return ;
	}
	int mid = (lf + rg) >> 1;
	build(o << 1, lf, mid);
	build(o << 1 | 1, mid + 1, rg);
	update(o);
}

void pushdown(int o) {
	if (flag[o]) {
		flag[o << 1] = flag[o << 1 | 1] = 1;
		tag[o << 1] = mul(tag[o << 1], tag[o]);
		tag[o << 1 | 1] = mul(tag[o << 1 | 1], tag[o]);
		f[o << 1] = mul(f[o << 1], tag[o]);
		f[o << 1 | 1] = mul(f[o << 1 | 1], tag[o]);
		tag[o] = newnode();
		tag[o].a[1][1] = tag[o].a[2][2] = 1;
		flag[o] = 0;
	}
}

void modify(int o, int lf, int rg, int L, int R, Mat d) {
	if (L <= lf && rg <= R) {
		f[o] = mul(f[o], d);
		tag[o] = mul(tag[o], d);
		flag[o] = 1;
		return ;
	}
	pushdown(o);
	int mid = (lf + rg) >> 1;
	if (L <= mid) modify(o << 1, lf, mid, L, R, d);
	if (R > mid) modify(o << 1 | 1, mid + 1, rg, L, R, d);
	update(o);
} 

Mat query(int o, int lf, int rg, int L, int R) {
	if (L <= lf && rg <= R) {
		return f[o];
	}
	pushdown(o);
	Mat rt = newnode();
	int mid = (lf + rg) >> 1;
	if (L <= mid) rt = add(rt, query(o << 1, lf, mid, L, R));
	if (R > mid) rt = add(rt, query(o << 1 | 1, mid + 1, rg, L, R));
	return rt;
}

int main() {
	n = read(), m = read();
	for (int i = 1; i <= n; i++) a[i] = read();
	s = newnode();
	s.a[1][1] = s.a[1][2] = s.a[2][1] = 1;
	build(1, 1, n);
	while (m--) {
		int opt = read();
		if (opt == 1) {
			int L = read(), R = read();
			ll x = read();
			Mat tmp = mpow(s, x);
			modify(1, 1, n, L, R, tmp);
		//	Mat now = query(1, 1, n, 13, 13);
		//	printf("%lld\n", (now.a[1][1] + now.a[1][2]) % Mod);
		//	Mat noww = query(1, 1, n, 14, 14);
		//	printf("%lld\n", (noww.a[1][1] + noww.a[1][2]) % Mod);
			//printf("%lld\n", (now.a[1][1] + now.a[1][2] + noww.a[1][1] + noww.a[1][2]) % Mod);
		} else {
			int L = read(), R = read();
			Mat x = query(1, 1, n, L, R);
			printf("%lld\n", (x.a[1][1] + x.a[1][2]) % Mod);
		}
	}
	return 0;
}
/*
18 31
1 1 2 2 2 1 2 1 2 2 2 2 1 1 1 2 2 1
1 4 7 2
1 9 10 1
1 2 4 2
1 15 18 2
1 3 10 2
1 7 8 1
1 13 18 2
1 15 17 2
1 16 17 1
1 16 16 2
1 10 12 1
1 4 13 2
1 3 8 1
1 7 9 1
1 13 18 2
1 3 14 2
1 2 2 1
1 14 17 1
1 9 18 1
1 7 17 1
1 2 5 1
1 8 13 2
1 12 18 1
2 13 14
2 15 18
1 14 14 2
1 8 14 2
1 3 11 2
1 17 17 2
1 7 10 2
2 3 12
*/


G - Cats Transport

 CodeForces - 311B 

题目大意:

小 S 是农场主,他养了 M MM 只猫,雇了 P PP 位饲养员。农场中有一条笔直的路,路边有 N NN 座山,从 1 11 到 N NN 编号。第 i ii 座山与第 i − 1 i-1i−1 座山之间的距离是 D i D_iDi​​​ 。饲养员都住在 1 11 号山上。

有一天,猫出去玩。第 iii 只猫去 H i H_iHi​号山玩,玩到时刻 T i T_iTi​停止,然后在原地等饲养员来接。饲养员们必须回收所有的猫。每个饲养员沿着路从 1 11 号山走到 N NN 号山,把各座山上已经在等待的猫全部接走。饲养员在路上行走需要时间,速度为 1 11 米每单位时间。饲养员在每座山上接猫的时间可以忽略,可以携带的猫的数量为无穷大。

例如有两座相距为 1 11 的山,一只猫在 2 22 号山玩,玩到时刻 3 33 开始等待。如果饲养员从 1 11 号山在时刻 2 22 或 3 33 出发,那么他可以接到猫,猫的等待时间为 0 00 或 1 11。而如果他于时刻 1 11 出发,那么他将于时刻 2 22 经过 2 22 号山,不能接到当时仍在玩的猫。

你的任务是规划每个饲养员从 1 11 号山出发的时间,使得所有猫等待时间的总和尽量小。饲养员出发的时间可以为负。

T时间到达d的饲养员和T - d从1出发的饲养员等价

可以把所有猫看成都在1号节点,对于出现的时间为T - d

sort一下之后就是将这么多只猫分成p份的最小权值

dp过程中可以进行斜率优化,复杂度m * p,可以滚动减少空间

#include<iostream>
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
#define db double
using namespace std;

ll read() {
	ll rt = 0, f = 1;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		if (ch == '-') f = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <='9') {
		rt = (rt << 3) + (rt << 1) + ch - '0';
		ch = getchar();
	}
	return rt * f;
}

const int maxn = 1e5 + 5;
ll dp[maxn][105], d[maxn], c[maxn], sum[maxn]; 

ll q[maxn], n, m, p;

db slope(int i, int j, int k) {
	return (1.0 * (sum[i] + dp[i][k - 1] - sum[j] - dp[j][k - 1])) / (1.0 * (i - j));
}

int main() {
	n = read(), m = read(), p = read();
	for (int i = 2; i <= n; i++) {
		d[i] = read();
		d[i] += d[i - 1];
	}
	for (int i = 1; i <= m; i++) {
		ll h = read(), t = read();
		c[i] = t - d[h];
	}
	sort(c + 1, c + 1 + m);
	for (int i = 1; i <= m; i++) sum[i] = sum[i - 1] + c[i];
	memset(dp, 0x3f, sizeof(dp));
	dp[0][0] = 0;
	for (int j = 1; j <= p; j++) {
		int head = 1, tail = 0;
		q[++tail] = 0;
		for (int i = 1; i <= m; i++) {
			while (head < tail && slope(q[head], q[head + 1], j) < 1.0 * c[i]) head++;
			dp[i][j] = min(dp[i][j], dp[q[head]][j - 1] + (i - q[head]) * c[i] - sum[i] + sum[q[head]]);
			while (head < tail && slope(q[tail - 1], q[tail], j) > slope(q[tail], i, j)) tail--;
			q[++tail] = i;
		}
	}
	cout << dp[m][p] << endl;
	return 0;
}

H的NTT乱搞不会,爪巴

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值