Gemini Boy - ACM之路~

随想

    还有47天就是南京现场赛了。凭心而论,压力很大,现在天天只能睡5,6个小时,就要爬起来坐到电脑前做题。当然这不能怪别的,只能怪自己在过去的一年多没有好好练,挖的坑太大,可能没有时间填坑了。但是既然努力了1年多了,就不想在这最后的几十天留下遗憾。

列一下ToDoList(自己之前搞的不错的东西就不列出来了):

1.动态规划

  • 数位DP
  • 树形DP
  • 状态压缩

2.数据结构

  • 树套树
  • CDQ分治
  • 树链剖分
  • 动态树

3.字符串

  • AC自动机
  • 后缀数组
  • hash
  • 后缀自动机

4.图论

  • 网络流
  • 连通分量

5.数学

  • 高斯消元
  • 概率与期望
  • 组合数学
  • 线性方程

 

要做的一些比赛:

POI 15-19th

Andrew Stankevich Contest 1-10

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=31687#overview

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=31688#overview

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=31294#overview

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=31535#overview

...(未完待续)

数位统计

先贴个模板:http://www.cnblogs.com/jffifa/archive/2012/08/17/2644847.html

题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=31294#overview

坑~

19th Polish Olympiad in Informatics

链接:http://main.edu.pl/en/archive/oi/19

Festival(Stage I):

Description
有n个正整数X1,X2,...,Xn,再给出m1+m2个限制条件,限制分为两类:
1. 给出a,b (1<=a,b<=n),要求满足Xa + 1 = Xb
2. 给出c,d (1<=c,d<=n),要求满足Xc <= Xd
在满足所有限制的条件下,求集合{Xi}大小的最大值。
Input
第一行三个正整数n, m1, m2 (2<=n<=600, 1<=m1+m2<=100,000)。
接下来m1行每行两个正整数a,b (1<=a,b<=n),表示第一类限制。
接下来m2行每行两个正整数c,d (1<=c,d<=n),表示第二类限制。
Output
一个正整数,表示集合{Xi}大小的最大值。
如果无解输出NIE。
Sample Input
4 2 2
1 2
3 4
1 4
3 1
Sample Output
3
Hint
X3=1, X1=X4=2, X2=3
这样答案为3。容易发现没有更大的方案。
 
做法就是类似于差分约束建图,然后在每个scc里判断是否满足限制条件。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
#include <stack>
using namespace std;

const int maxn = 1000;
const int inf = 1000000000;

struct Edge {
	int v, w;
	Edge() {}
	Edge(int vv, int ww) {
		v = vv; w = ww;
	}
};

vector<Edge> adj[maxn*2];
int idx, size;
int n, m1, m2, a, b;
int dist[maxn][maxn];
int dfn[maxn], low[maxn], stk[maxn], id[maxn];
bool vis[maxn];
stack<int> S;

inline int Myabs(int x) {
	if (x < 0)
		x = -x;
	return x;
}

void addEdge(int u, int v, int w) {
	adj[u].push_back(Edge(v, w));
}

void tarjan(int u) {
	dfn[u] = low[u] = ++idx;
	S.push(u); vis[u] = true;
	vector<Edge>::iterator it;
	for (it = adj[u].begin(); it != adj[u].end(); it++) {
		int v = it->v;
		if (dfn[v] == -1) {
			tarjan(v);
			low[u] = min(low[u], low[v]);
		} else if (vis[v]) {
			low[u] = min(low[u], dfn[v]);
		}
	}
	if (low[u] == dfn[u]) {
		size++;
		int v;
		do {
			v = S.top();
			S.pop();
			id[v] = size;
			vis[v] = false;
		} while (u != v);
	}
}

void clearAll() {
	for (int i = 0; i < maxn; i++)
		adj[i].clear();
	memset(dfn, -1, sizeof(dfn));
	memset(low, -1, sizeof(low));
	memset(vis, false, sizeof(vis));
	memset(id, 0, sizeof(id));
	memset(dist, 0, sizeof(dist));
	while (!S.empty()) S.pop();
}

void init() {
	scanf("%d %d %d", &n, &m1, &m2);
	for (int i = 0; i < m1; i++) {
		scanf("%d %d", &a, &b);
		addEdge(a, b, 1);
		addEdge(b, a, -1);
	}
	for (int i = 0; i < m2; i++) {
		scanf("%d %d", &a, &b);
		addEdge(a, b, 0);
	
}

void work() {
	for (int i = 1; i <= n; i++) {
		if (dfn[i] == -1)
			tarjan(i);
	}
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			if (i == j)
				dist[i][j] = 0;
			else
				dist[i][j] = -inf;
		}
	}
	for (int i = 1; i <= n; i++) {
		vector<Edge>::iterator it;
		for (it = adj[i].begin(); it != adj[i].end(); it++) {
			int j = it->v;
			if (id[i] == id[j])
				dist[i][j] = max(dist[i][j], it->w);
		}
	}
	for (int k = 1; k <= n; k++) {
		for (int i = 1; i <= n; i++) {
			if (dist[i][k] <= -inf)
				continue;
			for (int j = 1; j <= n; j++) {
				if (dist[k][j] <= -inf)
					continue;
				if (dist[i][k] + dist[k][j] > dist[i][j])
					dist[i][j] = dist[i][k] + dist[k][j];
			}
		}
	}
	for (int i = 1; i <= n; i++) {
		if (dist[i][i] > 0) {
			puts("NIE");
			return ;
		}
	}
	int result = 0;
	vector<int> ans;
	memset(vis, false, sizeof(vis));
	for (int i = 1; i <= n; i++) {
		ans.clear();
		if (vis[i] == true)
			continue;
		for (int j = 1; j <= n; j++) {
			if (id[i] == id[j]) {
				vis[j] = true;
				ans.push_back(j);
			}
		}
		int tmp = 0;
		for (int j = 0; j < ans.size(); j++) {
			for (int k = 0; k < ans.size(); k++) {
				tmp = max(tmp, Myabs(dist[ans[j]][ans[k]])+1);
			}
		}
		result += tmp;
	}
	printf("%d\n", result);
}

int main() {
	clearAll();
	init();
	work();
	return 0;
}

Letters(Stage I):

Description
给出两个长度相同且由大写英文字母组成的字符串A、B,保证A和B中每种字母出现的次数相同。
现在每次可以交换A中相邻两个字符,求最少需要交换多少次可以使得A变成B。
Input
第一行一个正整数n (2<=n<=1,000,000),表示字符串的长度。
第二行和第三行各一个长度为n的字符串,并且只包含大写英文字母。
Output
一个非负整数,表示最少的交换次数。
Sample Input
3
ABC
BCA
Sample Output
2
Hint
ABC -> BAC -> BCA
 
其实就是求逆序对。BIT维护。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
#include <vector>
using namespace std;

const int maxn = 1001000;

char str1[maxn], str2[maxn];
vector<int> adj1[maxn], adj2[maxn];
int len, sum[maxn], pos[maxn];

int main() {
	scanf("%d %s %s", &len, str1, str2);
	for (int i = 0; i < len; i++) {
		adj1[str1[i]-'A'].push_back(i);
		adj2[str2[i]-'A'].push_back(i);
	}
	for (int i = 0; i < 26; i++) {
		for (int j = 0; j < adj1[i].size(); j++) {
			pos[adj1[i][j]] = adj2[i][j];
		}
	}
	long long ans = 0;
	for (int i = len - 1; i >= 0; i--) {
		for (int j = pos[i]; j; j -= j & -j)
			ans += sum[j];
		for (int j = pos[i] + 1; j <= len; j += j & -j)
			sum[j]++;
	}
	printf("%lld\n", ans);
	return 0;
}

 

2013 ACM/ICPC Asia Regional Online —— Warmup

链接:http://acm.hdu.edu.cn/search.php?field=problem&key=2013%20ACM/ICPC%20Asia%20Regional%20Online%20%A1%AA%A1%AA%20Warmup&source=1&searchmode=source

A题(HDU 4706):无意义的题,就贴个代码吧

#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;

void get(int x, int n) {
	int y = x + 2 * (n - 1);
	y %= 26;
	for (int i = 1; i <= n; i++) {
		printf("%c", 'a'+(x+i-1)%26);
		for (int j = n-i-1; j >= 1; j--)
			printf(" ");
		if (i > 1 && i < n)
			printf("%c", 'a'+(y+1-i+26)%26);
		for (int j = 1; j <= i-2; j++)
			printf(" ");
		printf("%c\n", 'a'+(y+i-1)%26);
	}
}

int main() {
	int x = 0;
	for (int i = 3; i <= 10; i++) {
		get(x, i);
		x = (x+2*i+i-2) % 26;
	}
	return 0;
}

 

2012 Asia Chengdu Regional Contest

链接:http://acm.hdu.edu.cn/search.php?field=problem&key=2012%20Asia%20Chengdu%20Regional%20Contest%20&source=1&searchmode=source

A题(HDU 4464):无意义的题。。就贴个代码吧。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;

const int maxn = 10010;

int n, cas;
char ch[maxn];

int main() {
	cas = 0;
	while (~scanf("%d", &n)) {
		int ans = 0;
		for (int i = 0; i < n; i++) {
			scanf("%s", ch);
			int len = strlen(ch);
			int sum = 0;
			for (int i = 0; i < len; i++) {
				sum += (int)ch[i];
			}
			if (ans < sum)
				ans = sum;
		}
		printf("Case %d: %d\n", ++cas, ans);
	}
	return 0;
}

B题(HDU 4465):这题是道求期望的题,还算比较简单。公式很容易得到:

但是因为组合数比较大,不能直接算。为了保证精度,可以先求log,然后再用乘方,算回来。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;

int n, cas = 0;
double p;

int main() {
	while (~scanf("%d %lf", &n, &p)) {
		printf("Case %d: ", ++cas);
		double q = 1 - p;
		if (fabs(p) < 1e-10 || fabs(q)<1e-10) {
			printf("%.6lf\n", 1.0 * n);
			continue;
		}
		double tmp = (n + 1) * log(p);
		double tem = (n + 1) * log(q);
		double ans = 0, t = 0, tt = 0, ttt = 0;
		for (int i = n + 1; i <= n + n; i++) {
			tt = t + tmp + (i-1-n) * log(q) + log(1.0+n+n-i);
			ttt = t + tem + (i-1-n) * log(p) + log(1.0+n+n-i);
			ans += exp(tt) + exp(ttt);
			t += log(1.0*i) - log(1.0*i-n);
		}
		printf("%.6lf\n", ans);
	}
	return 0;
}




Host by is-Programmer.com | Power by Chito 1.3.3 beta | © 2007 LinuxGem | Design by Matthew "Agent Spork" McGee