2019 icpc 南京网络赛

A题:二维偏序

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

using namespace std;

const int P = 1e5 + 10; 

int t, n, m, p, ans[P], b[P];
vector<int> c;
struct Node {
	int x, y, val, type, index;
	bool operator < (Node o) {
		return x < o.x || (x == o.x && y < o.y) || (x == o.x && y == o.y && type < o.type);
	}
} node[P*5];

void clear () {
	c.clear();
	memset(b, 0, sizeof(b));
	memset(ans, 0, sizeof(ans));
}

// 计算每个宫殿的值 
int cal (int x, int y) {
	x = x - n / 2 - 1;
	y = y - n / 2 - 1;
	int t = max(abs(x), abs(y));
	long long val;
	if (x >= y) val = (long long)n * n - 4 * (long long)t * t - 2 * t - x - y;
	else val = (long long)n * n - 4 * (long long)t * t + 2 * t + x + y;
	int ans = 0;
	while (val != 0) {
		ans += val % 10;
		val /= 10;
	}
	return ans;
}

void insert (int i, int x, int y, int type, int index) {
	node[i].x = x; 
	node[i].y = y; 
	node[i].type = type;
	node[i].index = index;
}

int find (int x) {
	int l = 0, r = c.size() - 1;
	while (l < r) {
		int mid = (l + r) / 2;
		if (c[mid] >= x) r = mid;
		else l = mid + 1;
	}
	if (c[l] > x) l--;
	return l + 1;
}

int ask (int x) {
	int ans = 0;
	for (; x; x -= x & - x) {
		ans = ans + b[x];
	}
	return ans;
}

void add (int x, int y) {
	for (; x <= c.size(); x += x & -x) {
		b[x] = b[x] + y;
	}
}

int main () {
	scanf("%d", &t);
	while (t--) {
		clear();
		scanf("%d%d%d", &n, &m, &p);
		for (int i = 0; i < m; i++) {
			scanf("%d%d", &node[i].x, &node[i].y);
			node[i].val = cal(node[i].x, node[i].y);
			node[i].type = 0;
			c.push_back(node[i].y);
		}
		for (int i = 0, x1, y1, x2, y2; i < p; i++) {
			scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
			// matrix[x2][y2] - matrix[x1-1][y2] - matrix[x2][y1-1] + matrix[x1-1][y1-1];
			insert(m + i * 4, x2, y2, 1, i);
			insert(m + i * 4 + 1, x1 - 1, y2, 2, i);
			insert(m + i * 4 + 2, x2, y1 - 1, 2, i);
			insert(m + i * 4 + 3, x1 - 1, y1 - 1, 1, i);
		}
		// 离散化y轴上的值 
		sort(c.begin(), c.end());
		c.erase(unique(c.begin(), c.end()), c.end());
		//  将node根据进行排序 
		sort(node, node + m + 4 * p);
		for (int i = 0; i < m + 4 * p ; i++) {
			if (node[i].type == 0) {
				// 当type == 0时代表是宫殿 
				add(find(node[i].y), node[i].val);
			} else if (node[i].type == 1) {
				// 当type == 1时代表,一个矩阵的值需要增加的部分 
				ans[node[i].index] += ask(find(node[i].y));
			} else {
				// 当type == 2时代表,一个矩阵的值需要减少的部分 
				ans[node[i].index] -= ask(find(node[i].y));
			}
		}
		for (int i = 0; i < p; i++) {
			printf("%d\n", ans[i]);
		}
	}
	return 0;
}

B题:迭代幂次,欧拉降幂

#include <cstdio> 
#include <cmath>

using namespace std;

int t, a, b, m;

// 欧拉函数,phi[x]等于不超过x且和x互素的整数个数。 
int phi (int x) {
	int m = (int) sqrt(x + 0.5);
	int ans = x;
	for (int i = 2; i <= m; i++) {
		if (x % i == 0) {
			ans = ans / i * (i - 1);
			while (x % i == 0) x /= i;
		}
	}
	if (x > 1) ans = ans / x * (x - 1);
	return ans;
}

// 快速幂 
int power (long long a, int b, int m) {
    long long ans = 1;
    while (b) {
        if (b & 1) ans = (ans * a) % m;
        a = (a * a) % m;
        b >>= 1;
    }
    return (int) ans;
}

// 欧拉降幂,处理幂 
int cal (int b, int m) {
	if (b < m && b) return b; // 需要注意b为0时的特殊情况 
	else return b % m + m;
}

int solve (int a, int b, int m) {
	if (b == 0) return 1;
	if (m == 1) return a;
	int val = solve(a, b - 1, phi(m));
	return power((long long)a, cal(val, phi(m)), m);
}

int main () {
	scanf("%d", &t);
	while (t--) {
		scanf("%d%d%d", &a, &b, &m);
		printf("%d\n", (solve(a, b, m)) % m);
	}
	return 0;
}

D题:期望
设d[i]为城市i到城市n花费的天数
设f[i]为城市i到城市n消耗量
设num[i]是城市i的出边个数
d[x] = (1 / (num[x] + 1)) * d[x] + (1 / (num[x] + 1)) * ∑d[y] + 1
f[x] = (1 / (num[x] + 1)) * f[x] + (1 / (num[x] + 1)) * ∑f[y] + d[x]
y是x的下一个城市

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1e5 + 10;
const int M = 2e5 + 10;

int t, n, m, num[N];
double d[N], f[N];
bool vis[N];
int head[N], Next[M], edge[M], tot;

void clear () {
	memset(head, 0, sizeof(head));
	memset(num, 0, sizeof(num));
	memset(vis, 0, sizeof(vis));
	d[n] = f[n] = 0;
	tot = 0;
}

void add (int a, int b) {
	tot++;
	Next[tot] = head[a];
	head[a] = tot;
	edge[tot] = b;
}

void dfs (int x) {
	if (vis[x]) return;
	vis[x] = true;
	double val1 = 0, val2 = 0;
	for (int i = head[x]; i; i = Next[i]) {
		int y = edge[i];
		dfs(y);
		val1 += d[y];
		val2 += f[y];
	}
	d[x] = (val1 + num[x] + 1) / num[x];
	f[x] = (val2 + (num[x] + 1) * d[x]) / num[x];
	
}

int main () {
	scanf("%d", &t);
	while (t--) {
		scanf("%d%d", &n, &m);
		clear();
		for (int i = 0, a, b; i < m; i++) {
			scanf("%d%d", &a, &b);
			add(a, b);
			num[a]++;
		}
		vis[n] = true;
		dfs(1);
		printf("%.2lf\n", f[1]);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值