20160815 训练记录

tonyfang posted @ 2016年8月15日 18:49 in 随笔 with tags C++ OI , 595 阅读

1. 给出n条水平直线和m条竖直直线,k个石头,石头只能放在直线交点,问最多能组成多少边平行于直线的矩形

$n, m \leq 30000, k \leq n \times m$

【题解】暴力即可。注意边界。

 

# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <algorithm>
# include <math.h>
# include <iostream>

using namespace std;

int n, m, k;
long long ans = 0;

inline long long get(int i, int j) {
	return (long long)i*(i-1)/2 * (long long)j*(j-1)/2;
}

int main() {
	freopen("rectangle.in", "r", stdin);
	freopen("rectangle.out", "w", stdout);
	
	int i;
	
	scanf("%d%d%d", &n, &m, &k);
	
	if(n>m) swap(n, m);
	
	int s = sqrt(k);
	if(s*s == k) i=s;
	else i=s+1;
	
	for (; i>=2; --i) {
		int j=k/i;
		if(min(i, j) > n || max(i, j) > m) continue;
		if(k%i == 0) {
			long long cur = get(i, j);
			if(cur > ans) ans = cur;
		} else {
			int res = k-i*j;
			long long cur=0;
//			cout << "i=" << i << endl;
			if (i == n && j == m) continue;
//			cout << "i=" << i << " j=" << j << endl;
			if (min(i, j+1) <= n && max(i, j+1) <= m) {
				int a = i, b = j+1, c = res;
//				printf("a=%d, b=%d, c=%d\n", a, b, c);
				cur = get(b, c) + get(a, b-1) - get(b-1, c);
//				printf("%lld %lld %lld\n", get(b, c), get(a, b-1), get(b-1, c));
				if(cur > ans) ans = cur;
			}
		}
	}
	
	cout << ans << endl;
	
	fclose(stdin);
	fclose(stdout);
	return 0;
}

2. 求斐波那契数列的第x~y项之和。T组询问。对$10^4$取模。

$x, y \leq 2^{31}-1$

【题解】

方法一:构造矩阵乘法,加入前缀和$s_{i-1}$和$s_{i-2}$两维转移。复杂度$O(4^{3}Tlogy)$

方法二:构造矩阵乘法,由于$s_{i} = f_{i+2} - 1$即可矩阵乘$f$,从而推出。复杂度$O(2^{3}Tlogy)$

方法三:由于对$10^4$取模,尾数每$1.5\times10^{4}$是一个循环,从而较快算出前缀和。复杂度$O(15000+T)$

我用的是方法一

 

# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <algorithm>
# include <iostream>

using namespace std;

struct matrix {
	int n, m, a[20][20];
} t1, t2, f1, f2, tem1, tem2;
const int MOD=1e4;

inline void add(int &x, int y) {
	y = y % MOD;
	x = (x+y) % MOD;
}

inline struct matrix mul(struct matrix a, struct matrix b) {
	struct matrix c;
	memset(c.a, 0, sizeof(c.a));
	c.n=a.n, c.m=b.m;
	for (int i=1; i<=c.n; ++i)
		for (int j=1; j<=c.m; ++j) 
			for (int k=1; k<=a.m; ++k) 
				add(c.a[i][j], a.a[i][k] * b.a[k][j]);
	return c;
}

inline struct matrix matrixpow(struct matrix a, int b) {
	struct matrix ret;
	memset(ret.a, 0, sizeof(ret.a));
	ret.n = 4, ret.m = 4;
	ret.a[1][1] = ret.a[2][2] = ret.a[3][3] = ret.a[4][4] = 1;
	while(b) {
		if(b&1) ret = mul(ret, a);
		a = mul(a, a);
		b>>=1; 
	}
	return ret;
}

inline void outputmatrix(matrix a) {
	for (int i=1; i<=a.n; ++i, printf("\n"))
		for (int j=1; j<=a.m; ++j) printf("%d ", a.a[i][j]);
}

int main() {
	freopen("fibonacci.in", "r", stdin);
	freopen("fibonacci.out", "w", stdout);
	int T;
	scanf("%d", &T);
	while(T--) {
		t1.n = t1.m = 4;
		memset(t1.a, 0, sizeof(t1.a));
		t1.a[1][1] = t1.a[1][2] = t1.a[2][1] = t1.a[3][1] = t1.a[3][3] = t1.a[4][3] = 1;
		t2 = t1;
		f1.n = 4, f1.m = 1;
		memset(f1.a, 0, sizeof(f1.a));
		f1.a[1][1] = f1.a[3][1] = 1;
		f2 = f1;
		// outputmatrix(f1), outputmatrix(t1);
		int x, y;
		scanf("%d%d", &x, &y);
		tem1 = matrixpow(t1, x-1);	
		tem2 = matrixpow(t2, y);
		f1 = mul(tem1, f1);
		f2 = mul(tem2, f2);
		printf("%d\n", (f2.a[3][1] - f1.a[3][1] + MOD) % MOD);
	}
	fclose(stdin);
	fclose(stdout);
	return 0;
}

3. 给出一张$n$个点$m$条边的无向连通图,求删去边使他成为一棵树后,1号点到其他点最短距离没变的方案数。

$ n \leq 1000, m \leq \frac{n(n-1)}{2}$

【题解】

我用的是spfa,和下面题解写的差不多。

100%:

首先考虑离 1 点最近的那个点,一定和 1 点只连着一条边,则这条边是必选的;然后考察第二近的点,一种可能是和 1 点直接连的边比较近,一种可能是经过刚才最近的那个点再到 1 点的路比较近,不管是哪一种,选择都是唯一的,而剩下第三种可能是两者距离相同,这样的话两者选且只能选一个。以此类推,假设现在已经构造好了前 k 个点的一棵子树,看剩余点中到 1 点最近的点,这个点到 1 点有 k 种方法(分别是和那 k 个点连边), 其中有 m 个是可以保持最短距离的,则这一步可选的边数就是 m。一直构造,把方法数累乘,就能得到最后的结果。整个过程可以很好的符合 dijkstra 的过程,而生成树的步骤和 prim 如出一辙。
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <algorithm>
# include <iostream>
# include <queue>
using namespace std;

int n, m;
bool vis[1010];
int we[1010][1010], d[1010];
int head[1010], next[2000020], to[2000020], w[2000020], tot=0;
const long long mod = 2147483647;
long long ans=1;
struct node {
	int id, d;
}a[1010];
queue<int> q;

inline bool cmp(node a, node b) {
	return a.d < b.d;
}

inline void add(int u, int v, int tw) {
	++tot;
	next[tot]=head[u];
	head[u]=tot;
	to[tot]=v;
	w[tot]=tw;
	we[u][v]=tw;
}

int main() {
	freopen("treecount.in", "r", stdin);
	freopen("treecount.out", "w", stdout);
	scanf("%d%d", &n, &m);
	for (int i=1; i<=n; ++i) for (int j=1; j<=n; ++j) we[i][j] = 1000000000;
	for (int i=1, u, v, tw; i<=m; ++i) {
		scanf("%d%d%d", &u, &v, &tw);
		add(u, v, tw);
		add(v, u, tw);
	}
	q.push(1); vis[1]=1, d[1]=0;
	for (int i=2; i<=n; ++i) d[i] = 1000000000;
	while(!q.empty()) {
		int top=q.front(); q.pop(); vis[top]=0;
		for (int i=head[top]; i; i=next[i]) 
			if(d[to[i]] > d[top] + w[i]) {
				d[to[i]] = d[top] + w[i];
				if(!vis[to[i]]) {
					vis[to[i]] = 1;
					q.push(to[i]);
				}
			}
	}
	for (int i=1; i<=n; ++i) a[i].id=i, a[i].d=d[i];
	sort(a+1, a+n+1, cmp);
	for (int i=2; i<=n; ++i) {
		long long cur=0;
		for (int j=1; j<i; ++j) 
			if(a[i].d == a[j].d + we[a[i].id][a[j].id]) ++cur;
		ans = ans * cur % mod;
	}
	cout << ans << endl;
	fclose(stdin);
	fclose(stdout);
	return 0;
}

 
jnanabhumiap.in 说:
2023年6月16日 14:53

Jnanabhumi AP is a startup by passionate webmasters and bloggers who have passion to provide engaging content which is accurate, interesting and worthy to read. We are mope like a web community where you can find different jnanabhumiap.in information’s, resources, topics on day to day incidents or news. We provide you the finest of web content on each and every topics possible with help of editorial and content team.


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter