2017 Wuhan University Programming Contest (Online Round)(补题补题)

本文解析了多个算法题目,包括计算两地间相遇时间、树形结构的染色问题、字符串处理问题、矩阵快速幂以及求逆序数等。每道题都提供了清晰的思路说明和完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

A

设S是两地的总距离, x是从west方向过来的车的速度, y是east方向过来的车的速度,根据题意有

S = 60 / y (x + y)

2S = (S - 90 + 60) / y (x + y)

比一下就出来了


B

这题挺有意思的、

题意:就说一颗n个节点,n-1条边,有m种颜色,然后给出每一个节点能涂上的颜色,现在要求相邻的两个节点之间颜色不能相同,问一共有多少种涂色方案

思路:dp1[i][j] 代表以点i为节点的子树在节点i涂上颜色j时候的总方案数,dp2[i]代表以节点i为子树的方案数

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cctype>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <string>
#include <stack>
#include <map>
#include <set>
#include <utility>

using namespace std;
#define LL long long
#define pb push_back
#define mk make_pair
#define pill pair<int, int>
#define mst(Arr, x)	memset(Arr, x, sizeof(Arr))
#define REP(i, x, n)	for(int i = x; i < n; ++i)
const int qq = 1e4 + 10;
const int MOD = 1e7 + 9;
vector<int> G[qq];
LL dp1[qq][23], dp2[qq];
int color[qq][23];
int n, m;
void Init(){
	REP(i, 0, n + 1){
		G[i].clear();
	}
	mst(dp2, 0);
}
void Dfs(int u, int fa){
	for(int i = 1; i <= m; ++i)
		dp1[u][i] = color[u][i];
	for(int v : G[u]){
		if(v == fa)	continue;
		Dfs(v, u);
		for(int i = 1; i <= m; ++i){
			dp1[u][i] *= (dp2[v] - dp1[v][i] + MOD) % MOD;
			dp1[u][i] %= MOD;
		}
	}
	for(int i = 1; i <= m; ++i)	dp2[u] += dp1[u][i];
	dp2[u] %= MOD;
}

int main(){
	while(scanf("%d%d", &n, &m) != EOF){
		Init();
		REP(i, 1, n){
			int a, b;	scanf("%d%d", &a, &b);
			G[a].pb(b), G[b].pb(a);
		}
		REP(i, 0, n)
			REP(j, 0, m){
				scanf("%d", &color[i + 1][j + 1]);
			}
		Dfs(1, -1);
		printf("%lld\n", dp2[1]);
	}
	return 0;
}


C

题意:你可以删除一些数,要求剩下组成的数可以被6整除,并且不含前导零,问最多可以剩下多少位数

思路:dp[i][j]代表前i位在余数为j的时候的最大位数,注意0存在的情况

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cctype>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <string>
#include <stack>
#include <map>
#include <set>
#include <utility>

using namespace std;
#define LL long long
#define pb push_back
#define mk make_pair
#define pill pair<int, int>
#define mst(Arr, x)	memset(Arr, x, sizeof(Arr))
#define REP(i, x, n)	for(int i = x; i < n; ++i)
const int qq = 1e5 + 10;
const int INF = 1e9 + 10;
char st[qq];
int dp[qq][7];

int main(){
	while(scanf("%s", st + 1) != EOF){
		int n = strlen(st + 1);
		for(int i = 0; i <= n; ++i)
			for(int j = 0; j < 6; ++j)
				dp[i][j] = -INF;
		int ans = -INF;
		for(int i = 1; i <= n; ++i)	if(st[i] == '0')	ans = 1;
		for(int i = 1; i <= n; ++i){
			int t = st[i] - '0';
			if(t != 0)	dp[i][t % 6] = 1;
			for(int j = 0; j < 6; ++j)	dp[i][j] = max(dp[i][j], dp[i - 1][j]);
			for(int j = 0; j < 6; ++j)	dp[i][(j * 10 + t) % 6] = max(dp[i][(j * 10 + t) % 6], dp[i - 1][j] + 1);
			ans = max(ans, dp[i][0]);	
		}
		if(ans > 0)	printf("%d\n", ans);
		else	printf("-1s\n");
	}
	return 0;
}


E

矩阵快速幂的裸题

 令C=A*A,那么C(i,j)=ΣA(i,k)*A(k,j),实际上就等于从点i到点j恰好经过2条边的路径数(枚举k为中转点)。

只是这里是在k步内达到就可以了,也就是你到达n点后就可以了,但是快速幂还要继续下去,所以mar[n][n] = 1

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cctype>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <string>
#include <stack>
#include <map>
#include <set>
#include <utility>

using namespace std;
#define LL long long
#define pb push_back
#define mk make_pair
#define pill pair<int, int>
#define mst(Arr, x)	memset(Arr, x, sizeof(Arr))
#define REP(i, x, n)	for(int i = x; i <= n; ++i)
const int qq = 105;
const int MOD = 1e9 + 7;
int n, m, p;
struct Rec{
	LL mar[qq][qq];
	Rec(){
		mst(mar, 0);
	}
	Rec operator * (const Rec &a)const{
		Rec tmp;
		REP(i, 1, n)
			REP(j, 1, n){
				tmp.mar[i][j] = 0;
				REP(k, 1, n){
					tmp.mar[i][j] = (tmp.mar[i][j] + mar[i][k] * a.mar[k][j] + MOD) % MOD;
					tmp.mar[i][j] = (tmp.mar[i][j] + MOD) % MOD;
				}
			}
		return tmp;
	}
}ans;
Rec Quick(){
	Rec tmp;
	for(int i = 1; i <= n; ++i)
        tmp.mar[i][i] = 1;
	while(p){
		if(p & 1)	tmp = tmp * ans;
		p >>= 1;
		ans = ans * ans;
	}
	return tmp;
}
int main(){
	scanf("%d%d", &n, &m);
	REP(i, 1, m){
		int a, b;	scanf("%d%d", &a, &b);
		if(a != n)	ans.mar[a][b] = 1;
	 	if(b != n)	ans.mar[b][a] = 1;
	}
	ans.mar[n][n] = 1;
	scanf("%d", &p);
	Rec t;
	t = Quick();
	printf("%lld\n", (t.mar[1][n] + MOD) % MOD);
	return 0;
}



G

这题就是个求逆序数。

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cctype>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <string>
#include <stack>
#include <map>
#include <set>
#include <utility>

using namespace std;
#define LL long long
#define pb push_back
#define mk make_pair
#define pill pair<int, int>
#define mst(Arr, x)	memset(Arr, x, sizeof(Arr))
#define REP(i, x, n)	for(int i = x; i < n; ++i)
const int qq = 1e6 + 10;
int sum[qq], num[qq];
int n;
int lowbit(int x){
	return x&(-x);
}
int GetSum(int x){
	int ans = 0;
	while(x > 0){
		ans += sum[x];
		x -= lowbit(x);
	}
	return ans;
}
void UpDate(int x){
	while(x <= qq){
		sum[x] += 1;
		x += lowbit(x);
	}
}

int main(){
	while(scanf("%d", &n) != EOF){
		mst(sum, 0);
		REP(i, 0, n){
			scanf("%d", num + i);
		}
		LL ans = 0;
		for(int i = n - 1; i >= 0; --i){
			ans += GetSum(num[i] - 1);
			UpDate(num[i]);
		}
		printf("%lld\n", ans);
	}
	return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值