2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛

A

题意:i 猴子 喜欢 j类型的水果, j类型的水果位于 k位置,问所有猴子喜欢类型的水果在什么地方能找到

思路:把喜欢类型j的水果压到同一个数组里面,然后对于j类型水果喜欢k说过,直接再对猴子进行加答案

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <string>
#include <vector>
#include <queue>
#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(a, b)	memset(a, b, sizeof a)
#define REP(i, x, n)	for(int i = x; i <= n; ++i)
const int MOD = 1e9 + 7;
const int qq = 50 + 10;
const int INF = 1e9 + 10;
vector<int> G[qq];
set<int> st[qq];
int n, m;

int main(){
	int t;	scanf("%d", &t);
	while(t--) {
		scanf("%d%d", &n, &m);
		for(int a, b, i = 0; i < n; ++i) {
			scanf("%d%d", &a, &b);
			G[b].pb(a);
		}
		for(int a, b, i = 0; i < m; ++i) {
			scanf("%d%d", &a, &b);
			for(int j = 0; j < (int)G[a].size(); ++j) {
				st[G[a][j]].insert(b);
			}
		}
		set<int>::iterator it;
		for(int i = 0; i <= 50; ++i) {
			if(st[i].size() == 0)	continue;
			for(it = st[i].begin(); it != st[i].end(); ++it) {
				printf("%d %d\n", i, *it);
			}
		}
		for(int i = 0; i <= 50; ++i) {
			G[i].clear();
			st[i].clear();
		}
		puts("");
	}
	return 0;
}

C

#include <cstring>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <string>
#include <vector>
#include <queue>
#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(a, b)	memset(a, b, sizeof a)
#define REP(i, x, n)	for(int i = x; i <= n; ++i)
const int MOD = 1e9 + 7;
const int qq = 2e5 + 10;
const int INF = 1e9 + 10;
int n, b;
int c[qq];

int main(){
	int t;	scanf("%d", &t);
	while(t--) {
		scanf("%d%d", &n, &b);
		for(int i = 1; i <= n; ++i) {
			scanf("%d", c + i);
		}
		bool flag = true;
		int sum = c[1];
		for(int x, i = 2; i <= n; ++i) {
			scanf("%d", &x);
			if(sum - x * b >= 0) {
				sum -= x * b;
				sum += c[i];
			} else {
				flag = false;
			}
		}
		if(!flag)	puts("No");
		else	puts("Yes");
	}
	return 0;
}	


E

队友打表打出来的结果

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
const int MOD = 1e9 + 7;
LL a[25]={1,8,49,288,1681,9800,57121,332928,1940449,
          11309768,65918161,384199200,2239277041,13051463048,
          76069501249,443365544448,2584123765441,15061377048200,
          87784138523761,511643454094368,2982076586042449};
int main() {
    int t,cas=1;
    scanf("%d",&t);
    while(t--) {
        LL n;
        scanf("%lld",&n);
        for(int i=0;i<21;i++)
            if(n<=a[i]) {
                printf("Case #%d: %lld\n",cas++,a[i]);
                break;
            }
    }
    return 0;
}

F

题意:问最少加多少天边整个图能成为强联通图

思路:Tarjan缩点后统计入度为0的个数和出度为0的个数,取最大值即可

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <string>
#include <vector>
#include <queue>
#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(a, b)	memset(a, b, sizeof a)
#define REP(i, x, n)	for(int i = x; i <= n; ++i)
const int MOD = 1e9 + 7;
const int qq = 1e4 + 10;
const int INF = 1e9 + 10;
int belong[qq], dfn[qq], low[qq], Stack[qq];
int ind[qq], outd[qq];
bool instack[qq];
int n, m, Bcnt, Time, top;
vector<int> G[qq];
void Init() {
	mst(instack, false);
	mst(dfn, 0);
	Bcnt = Time = top = 0;
	for(int i = 0; i <= n; ++i) {
		G[i].clear();
	}
	mst(ind, 0);
	mst(outd, 0);
}
void Tarjan(int u) {
	low[u] = dfn[u] = ++Time;
	Stack[++top] = u;
	instack[u] = true;
	int sz = G[u].size();
	for(int i = 0; i < sz; ++i) {
		int v = G[u][i];
		if(!dfn[v]) {
			Tarjan(v);
			low[u] = min(low[u], low[v]);
		} else if(instack[v]) {
			low[u] = min(low[u], dfn[v]);
		}
	}
	if(low[u] == dfn[u]) {
		++Bcnt;
		int v;
		do {
			v = Stack[top--];
			instack[v] = false;
			belong[v] = Bcnt;
		}while(v != u);
	}
}

int main(){
	int t;	scanf("%d", &t);
	while(t--) {
		scanf("%d%d", &n, &m);
		Init();
		for(int a, b, i = 0; i < m; ++i) {
			scanf("%d%d", &a, &b);
			G[a].pb(b);
		}
		for(int i = 1; i <= n; ++i) {
			if(!dfn[i])	Tarjan(i);
		}
		if(Bcnt == 1) {
			printf("0\n");
			continue;
		}
		for(int i = 1; i <= n; ++i) {
			int sz = G[i].size();
			for(int j = 0; j < sz; ++j) {
				if(belong[i] == belong[G[i][j]])	continue;
				outd[belong[i]]++;
				ind[belong[G[i][j]]]++;
			}
		}
		int a = 0, b = 0;
		for(int i = 1; i <= Bcnt; ++i) {
			if(ind[i] == 0)	a++;
			if(outd[i] == 0)	b++;
		}
		printf("%d\n", max(a, b));
	}
	return 0;
}

G

题意:给出n次操作,Q 表示询问区间l r内有多少个字符串T, C 表示把S字符串中某一个位置的字符改变

思路:注意到T最大也只有10,所以我们可以考虑暴力更新,如果某一个位置的字符改变,最多会影响连续的|T|个串,所以我们每次更改的时候只需要对这部分进行更新即可,用树状数组维护前缀和

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <string>
#include <vector>
#include <queue>
#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(a, b)	memset(a, b, sizeof a)
#define REP(i, x, n)	for(int i = x; i <= n; ++i)
const int MOD = 1e9 + 7;
const int qq = 1e5 + 10;
const int INF = 1e9 + 10;
int sum[qq], num[qq];
int n, m;
char S[qq], T[20];
char a[5], b[5];
bool Isequal(int l, int r, int x, int y) {
	int cur = x;
	for(int i = l; i <= r; ++i, ++cur) {
		if(S[i] != T[cur])	return false;
	}
	return true;
}
void UpDate(int x, int val, int lens) {
	while(x <= lens) {
		sum[x] += val;
		x += x & (-x);
	}
}
int GetSum(int x) {
	int ans = 0;
	while(x > 0) {
		ans += sum[x];
		x -= x & (-x);
	}
	return ans;
}

int main(){
	int t;	scanf("%d", &t);
	while(t--) {
		mst(sum, 0);
		mst(num, 0);
		scanf("%d", &n);
		scanf("%s%s", S + 1, T + 1);
		int lens = strlen(S + 1);
		int lent = strlen(T + 1);
		for(int i = lent; i <= lens; ++i) {
			if(Isequal(i - lent + 1, i, 1, lent)) {
				num[i] = 1;
			} else {
				num[i] = 0;
			}
	//		printf("%d", num[i]);
			if(num[i])	UpDate(i, 1, lens);
		}
		for(int i = 0; i < n; ++i) {
			scanf("%s", a);
			if(a[0] == 'Q') {
				int l, r;	scanf("%d%d", &l, &r);
				if(r - l + 1 < lent) {
					puts("0");
					continue;
				}
				printf("%d\n", GetSum(r) - GetSum(l + lent - 1 - 1));
			} else {
				int pos;	scanf("%d", &pos);
				scanf("%s", a);
				if(a[0] == S[pos])	continue;
				S[pos] = a[0];
				for(int j = pos; j < pos + lent && j <= lens; ++j) {
					if(j - lent + 1 < 1)	continue;
					if(Isequal(j - lent + 1, j, 1, lent)) {
						if(!num[j]) {
							num[j] = 1;
							UpDate(j, 1, lens);
						}
					} else {
						if(num[j]) {
							num[j] = 0; 
							UpDate(j, -1, lens);
						}
					}
				}
				/*for(int j = 1; j <= lens; ++j) {
					printf("%d", num[j]);
				}*/
			}
		}
		puts("");
	}
	return 0;
}


H

题意:求有向图的最长链

思路:dp[i]代表以i结尾的最长链,然后我们可以借助有向图的拓扑结构更新答案

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <string>
#include <vector>
#include <queue>
#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(a, b)	memset(a, b, sizeof a)
#define REP(i, x, n)	for(int i = x; i <= n; ++i)
const int MOD = 1e9 + 7;
const int qq = 1e4 + 10;
const int INF = 1e9 + 10;
vector<int > G[qq], f[qq];
int deg[qq], dp[qq];
int n, m;
void Bfs() {
	queue<int> Q;
	for(int i = 1; i <= n; ++i) {
		if(deg[i] == 0)	Q.push(i);
	}
	while(!Q.empty()) {
		int u = Q.front();
		Q.pop();
		for(int i = 0; i < (int)G[u].size(); ++i) {
			int v = G[u][i];
			int c = f[u][i];
			dp[v] = max(dp[v], dp[u] + c);
			deg[v]--;
			if(!deg[v])	Q.push(v);
		}
	}
}

int main(){
	int t;	scanf("%d", &t);
	while(t--) {
		mst(deg, 0);
		mst(dp, 0);
		scanf("%d%d", &n, &m);
		for(int i = 0; i <= n; ++i) {
			G[i].clear();
			f[i].clear();
		}
		for(int a, b, c, i = 0; i < m; ++i) {
			scanf("%d%d%d", &a, &b, &c);
			G[a].pb(b), f[a].pb(c);
			deg[b]++;
		}
		Bfs();
		int maxn = 0;
		for(int i = 1; i <= n; ++i) {
			maxn = max(maxn, dp[i]);
		}
		printf("%d\n", maxn);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ACM-ICPC(国际大学生程序设计竞)是一项面向大学生的计算机编程竞,涉及算法和数据结构等领域。在比中,选手需要解决一系列编程问题,使用合适的算法和数据结构来实现正确和高效的解决方案。 对于整理ACM-ICPC模板,以下是一些建议: 1. 了解比要求:首先,你需要了解ACM-ICPC的具体要求和规则。这包括了解比所涉及的算法和数据结构,以及题目的类型和难度等。 2. 收集资料:收集与ACM-ICPC相关的资料,包括经典算法和数据结构的实现代码、常见问题的解题思路等。可以参考教材、博客、论文等资源。 3. 整理模板:将收集到的资料整理成模板。可以按照算法和数据结构的分类进行整理,例如排序算法、图算法、字符串算法等。对每个模板,添加必要的注释和示例代码,以便理解和使用。 4. 测试代码:对每个模板编写测试代码,确保它们的正确性和可靠性。可以使用已知的测试用例或自行设计测试用例。 5. 更新与扩充:定期更新和扩充模板,以适应ACM-ICPC中新出现的算法和数据结构。同时,根据自己的经验和理解,对模板进行优化和改进。 6. 练习和复习:在比之前,利用整理好的模板进行练习和复习。尝试解决一些经典问题,使用模板中的算法和数据结构进行实现,并进行优化。 希望这些建议对你整理ACM-ICPC模板有所帮助!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值