gym100712 ACM Amman Collegiate Programming Contest

非常水的手速赛,大部分题都是没有算法的。巨慢手速,老年思维。2个小时的时候看了下榜,和正常人差了3题(,最后还没写完跑去吃饭了..

A 水 Sort 比大小

/** @Date    : 2017-09-01 12:32:08
  * @FileName: A.cpp
  * @Platform: Windows
  * @Author  : Lweleth (SoungEarlf@gmail.com)
  * @Link    : https://github.com/
  * @Version : $Id$
  */
#include <bits/stdc++.h>
#define LL long long
#define PII pair<int ,int>
#define MP(x, y) make_pair((x),(y))
#define fi first
#define se second
#define PB(x) push_back((x))
#define MMG(x) memset((x), -1,sizeof(x))
#define MMF(x) memset((x),0,sizeof(x))
#define MMI(x) memset((x), INF, sizeof(x))
using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 1e5+20;
const double eps = 1e-8;

struct yuu
{
	string na;
	int s, p;
}a[110];

int cmp(yuu a, yuu b)
{
	if(a.s == b.s)
		return a.p < b.p;
	return a.s > b.s;
}
int main()
{
	int T;
	cin >> T;
	while(T--)
	{
		int n;
		cin >> n;
		int s, p;
		string na;
		for(int i = 0; i < n; i++)
		{
			cin >> a[i].na >> a[i].s >> a[i].p;  
		}
		sort(a, a + n, cmp);
		cout << a[0].na << endl;
	}
    return 0;
} 

B 水 枚举位置 猜拳,已经给定了出拳顺序,枚举石布临界,布剪临界的两个位置就好

/** @Date    : 2017-09-01 13:37:22
  * @FileName: B.cpp
  * @Platform: Windows
  * @Author  : Lweleth (SoungEarlf@gmail.com)
  * @Link    : https://github.com/
  * @Version : $Id$
  */
#include <bits/stdc++.h>
#define LL long long
#define PII pair<int ,int>
#define MP(x, y) make_pair((x),(y))
#define fi first
#define se second
#define PB(x) push_back((x))
#define MMG(x) memset((x), -1,sizeof(x))
#define MMF(x) memset((x),0,sizeof(x))
#define MMI(x) memset((x), INF, sizeof(x))
using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 1e5+20;
const double eps = 1e-8;


int r[1100], s[1100], p[1100];
int n;
char a[1100];
int main()
{
	int T;
	cin >> T;
	while(T--)
	{
		int n;
		MMF(r);
		MMF(s);
		MMF(p);
		scanf("%d", &n);
		scanf("%s", a + 1);
		for(int i = 1; i <= n; i++)
		{
			if(a[i] == 'R')
				r[i]++;
			else if(a[i] == 'S')
				s[i]++;
			else p[i]++;
			r[i] += r[i - 1];
			s[i] += s[i - 1];
			p[i] += p[i - 1];
		}
		int ans = 0;
		for(int i = 0; i <= n; i++)
		{
			for(int  j = 0; j + i <= n; j++)
			{
				int w = s[i] - s[0] + r[i + j] - r[i] + p[n] - p[i + j];
				int l = p[i] - p[0] + s[i + j] - s[i] + r[n] - r[i + j];
				if(w > l)
					ans++;
			}	
		}
		printf("%d\n", ans);
	}
    return 0;
} 

C 水 标记 一个*覆盖掉3个格子,先处理好,再扫一遍

/** @Date    : 2017-09-01 12:48:52
  * @FileName: C.cpp
  * @Platform: Windows
  * @Author  : Lweleth (SoungEarlf@gmail.com)
  * @Link    : https://github.com/
  * @Version : $Id$
  */
#include <bits/stdc++.h>
#define LL long long
#define PII pair<int ,int>
#define MP(x, y) make_pair((x),(y))
#define fi first
#define se second
#define PB(x) push_back((x))
#define MMG(x) memset((x), -1,sizeof(x))
#define MMF(x) memset((x),0,sizeof(x))
#define MMI(x) memset((x), INF, sizeof(x))
using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 1e5+20;
const double eps = 1e-8;


char a[110];
int vis[110];
int main()
{
	int T;
	cin >> T;
	while(T--)
	{
		int n;
		MMF(a);
		MMF(vis);
		cin >> n >> a;
		for(int i = 0; i < n; i++)
		{
			if(a[i] == '*')
				vis[i] = vis[i - 1] = vis[i + 1] = 1;
		}
		int cnt = 0;
		for(int i = 0; i < n; i++)
		{
			if(a[i] == '.' && vis[i] == 0)
				cnt++, vis[i] = vis[i + 1] = vis[i + 2] = 1;
			//cout << a[i];
		}
		cout << cnt << endl;
	}
    return 0;
} 

D DP 求把一个01串分成均不大于k长度且不是交替串的最小次数。对于任意位置起始的串,在延伸k长度内如果不是交替串那么可以进行转移,预处理出所有区间是否是交替串,DP转移,然后最后的k长度内里选个合法的最小值就行

/** @Date    : 2017-09-01 15:59:40
  * @FileName: D.cpp
  * @Platform: Windows
  * @Author  : Lweleth (SoungEarlf@gmail.com)
  * @Link    : https://github.com/
  * @Version : $Id$
  */
#include <bits/stdc++.h>
#define LL long long
#define PII pair
#define MP(x, y) make_pair((x),(y))
#define fi first
#define se second
#define PB(x) push_back((x))
#define MMG(x) memset((x), -1,sizeof(x))
#define MMF(x) memset((x),0,sizeof(x))
#define MMI(x) memset((x), INF, sizeof(x))
using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 1e5+20;
const double eps = 1e-8;

int vis[1010][1010];
int dp[1010];
char a[1010];
int n, k;

int main()
{
	int T;
	cin >> T;
	while(T--)
	{
		scanf("%d%d", &n, &k);
		scanf("%s", a + 1);
		MMF(vis);
		for(int i = 1; i <= n; i++)
		{
			for(int j = i + 1; j <= n; j++)
			{
				if(a[j] == a[j - 1] || vis[i][j - 1])
					vis[i][j] = 1;
				else vis[i][j] = 0;
			}
			vis[i][i] = 1;
		}


		MMI(dp);
		dp[1] = 0;
		for(int i = 1; i < n; i++)
		{
			for(int j = 1; j <= k; j++)
			{
				if(j + i <= n && vis[i][i + j - 1])
					dp[i + j] = min(dp[i] + 1, dp[i + j]);
			}
		}
		int mi = INF;
		for(int i = n - k + 1; i <= n; i++)
		{
			if(vis[i][n])
				mi = min(mi, dp[i]);
		}
		printf("%d\n", mi);
	}
    return 0;
} 

E 水 所有值均加上一定值使其中的最大值不超过100,问最终超过50的有多少个 之前题意还看错...英语太差

/** @Date    : 2017-09-01 12:39:07
  * @FileName: E.cpp
  * @Platform: Windows
  * @Author  : Lweleth (SoungEarlf@gmail.com)
  * @Link    : https://github.com/
  * @Version : $Id$
  */
#include <bits/stdc++.h>
#define LL long long
#define PII pair<int ,int>
#define MP(x, y) make_pair((x),(y))
#define fi first
#define se second
#define PB(x) push_back((x))
#define MMG(x) memset((x), -1,sizeof(x))
#define MMF(x) memset((x),0,sizeof(x))
#define MMI(x) memset((x), INF, sizeof(x))
using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 1e5+20;
const double eps = 1e-8;

int a[110];
int main()
{
	int T;
	cin >> T;
	while(T--)
	{
		int n;
		scanf("%d", &n);

		int ma = 0;
		for(int i = 0; i < n; i++)
		{
			scanf("%d", a + i);
			ma = max(ma, a[i]);
		}
		int cnt = 0;
		for(int i = 0; i < n; i++)
		{
			if(a[i] + 100 - ma >= 50)
				cnt++;
		}
		printf("%d\n", cnt);
	}
    return 0;
} 

F kruskal 给图问走遍所有点的一条路径中,求其中最大的边权值的最小值。 完全就是kruskal的过程。

/** @Date    : 2017-09-01 15:08:39
  * @FileName: F.cpp
  * @Platform: Windows
  * @Author  : Lweleth (SoungEarlf@gmail.com)
  * @Link    : https://github.com/
  * @Version : $Id$
  */
#include <bits/stdc++.h>
#define LL long long
#define PII pair<int ,int>
#define MP(x, y) make_pair((x),(y))
#define fi first
#define se second
#define PB(x) push_back((x))
#define MMG(x) memset((x), -1,sizeof(x))
#define MMF(x) memset((x),0,sizeof(x))
#define MMI(x) memset((x), INF, sizeof(x))
using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 1e5+20;
const double eps = 1e-8;

/*typedef struct sion
{
	int nxp;
	int dis;
	sion(){};
	sion(int n, int d):nxp(n),dis(d){}
}yuu;
vector<sion>edg[N];
int dic[N];
int vis[N];
int n, m;

int prim(int n)
{
	MMI(dic);
	MMF(vis);
	for(auto i : edg[1])
		dic[i.nxp] = i.dis;
	dic[1] = 0;
	vis[1] = 1;
	for(int i = 1; i <= n - 1; i++)
	{
		int tmp = INF, np;
		for(int j = 1; j <= n; j++)
		{
			if(!vis[j] && tmp > dic[j])
				tmp = dic[j], np = j;
		}
		if(tmp == INF)
			return 0;
		vis[np] = 1;
		for(auto j: edg[np])
		{
			if(!vis[j.nxp] && (j.dis) < dic[j.nxp])
				dic[j.nxp] = (j.dis);
		}
	}
	int ma = 0;
	for(int i = 2; i <= n; i++)
		ma = max(dic[i], ma);
	return ma;
}*/

struct edge
{
	int u, v, w;
}edg[N];
int n, m;
int fa[N];

int find(int x)
{
	if(x != fa[x])
		fa[x] = find(fa[x]);
	return fa[x];
}

int cmp(edge a, edge b)
{
	return a.w < b.w;
}

int join(int a, int b)
{
	int x = find(a);
	int y = find(b);
	if(x != y)
	{
		fa[y] = x;
		return 1;
	}
	return 0;
}
int main()
{
	int T;
	cin >> T;
	while(T--)
	{
		scanf("%d%d", &n, &m);
		for(int i = 0; i <= n; i++)
			fa[i] = i;
		for(int i = 0; i < m; i++)
		{
			int u, v, w;
			scanf("%d%d%d", &edg[i].u, &edg[i].v, &edg[i].w);
		}
		sort(edg, edg + m, cmp);

		int cnt = 0;
		int ma = 0; 
		for(int i = 0; i < m && cnt < n; i++)
		{
			if(join(edg[i].u, edg[i].v))
			{
				cnt++;
				ma = edg[i].w;
			}
		}
		printf("%d\n", ma);
	}
    return 0;
} 

G 状态枚举 最多10个物品要求取物品值的和不小于s,拿掉其中最小的后的值要小于s。 开始还在DP想啊想,就10个数用什么DP阿...

/** @Date    : 2017-09-01 14:31:31
  * @FileName: G.cpp
  * @Platform: Windows
  * @Author  : Lweleth (SoungEarlf@gmail.com)
  * @Link    : https://github.com/
  * @Version : $Id$
  */
#include <bits/stdc++.h>
#define LL long long
#define PII pair<int ,int>
#define MP(x, y) make_pair((x),(y))
#define fi first
#define se second
#define PB(x) push_back((x))
#define MMG(x) memset((x), -1,sizeof(x))
#define MMF(x) memset((x),0,sizeof(x))
#define MMI(x) memset((x), INF, sizeof(x))
using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 1e5+20;
const double eps = 1e-8;


int n, k;
int a[1210];
int main()
{
	int T;
	cin >> T;
	while(T--)
	{
		scanf("%d%d", &n, &k);
		for(int i = 0; i < n; i++)
			scanf("%d", a + i);
		int ma = 0;
		for(int i = 0; i < (1 << n); i++)
		{
			int s = 0;
			int mi = INF;
			int cnt = 0;
			for(int j = 0; j < n; j++)
			{
				if(((1 << j) & i))
					s += a[j], cnt++, mi = min(mi, a[j]);
			}
			if(s >= k && s - mi < k)
				ma = max(cnt, ma);
		}
		printf("%d\n", ma);
	}
    return 0;
} 

H(补) tarjan缩点 树的直径 题目问给图上加一条边,使图上的桥的数量最小,问数量。第一次碰到比较简单可以用tarjan,趁这个机会学一下...题目的思路是先求出所有桥,然后剩下的连通块分别缩点,重新建成树。此时树上的边都是桥,最后加边的话只要找树上两点距离最大的,也就是树的直径。这样就能保证包含最多的桥。

/** @Date    : 2017-09-04 21:09:38
  * @FileName: H tarjan缩点 树的直径.cpp
  * @Platform: Windows
  * @Author  : Lweleth (SoungEarlf@gmail.com)
  * @Link    : https://github.com/
  * @Version : $Id$
  */
#include <bits/stdc++.h>
#define LL long long
#define PII pair<int ,int>
#define MP(x, y) make_pair((x),(y))
#define fi first
#define se second
#define PB(x) push_back((x))
#define MMG(x) memset((x), -1,sizeof(x))
#define MMF(x) memset((x),0,sizeof(x))
#define MMI(x) memset((x), INF, sizeof(x))
using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 1e5+20;
const double eps = 1e-8;

struct sion
{
	int to, nxt;
	bool flag; //is bridge
};
sion edg[N*2];
int low[N], dfn[N];
int fa[N];
stack<int>stk;
bool instk[N];
int bridges;//桥
int block;//边双连通块
int idx;
////
int head[N], tot/*, nxt[N], isbg[N], to[N]*/;

void add(int x, int y)//前向星
{
	edg[tot].to = y;
	edg[tot].nxt = head[x];
	edg[tot].flag = 0;
	head[x] = tot++;
}
void init()
{
	MMF(dfn);
	MMF(instk);
	MMG(head);
	idx = block = bridges = tot = 0;
	while(!stk.empty())
		stk.pop();
}
void tarjan(int x, int pre)
{
	low[x] = dfn[x] = ++idx;
	stk.push(x);
	instk[x] = 1;
	for(int i = head[x]; ~i; i = edg[i].nxt)
	{
		int np = edg[i].to;
		if(np == pre)
			continue;
		if(!dfn[np])
		{
			tarjan(np, x);
			low[x] = min(low[np], low[x]);
			if(low[np] > dfn[x])
			{
				bridges++;
				edg[i].flag = 1;
				edg[i ^ 1].flag = 1;//注意双向
			}
		}
		else if(instk[np])
			low[x] = min(dfn[np], low[x]);
	} 
	if(low[x] == dfn[x])
	{
		int np;
		block++;
		do{
			np = stk.top();
			stk.pop();
			instk[np] = 0;
			fa[np] = block;
		}while(np != x);
	}
}
////
int k = 0, pos = -1;
int n, m;
int dfs(int x, int pre, int dep)
{
	if(k < dep)
		k = dep, pos = x;
	for(int i = head[x]; ~i; i = edg[i].nxt)
	{
		int np = edg[i].to;
		if(np == pre)
			continue;
		dfs(np, x, dep + 1);
	}
}
////
int xx[N], yy[N];
int main()
{
	int T;
	cin >> T;
	while(T--)
	{
		init();
		scanf("%d%d", &n, &m);
		for(int i = 1; i <= m; i++)
		{
			scanf("%d%d", xx + i, yy + i);
			add(xx[i], yy[i]);
			add(yy[i], xx[i]);
		}

		tarjan(1, 0);
		tot = 0;
		MMG(head);
		LL ans = 0;
		for(int i = 1; i <= m; i++)
		{
			int x = fa[xx[i]];
			int y = fa[yy[i]];
			if(x != y)
			{
				ans++;
				add(x, y);
				add(y, x);
			}
		}
		k = 0;
		dfs(1, -1, 0);
		k = 0;
		dfs(pos, -1, 0);
		printf("%lld\n", (ans - k)<0?0:ans-k);
	}
    return 0;
} 

I 暴力枚举 使用固定长度的区间,可以把区间的数字同时加,问最大使用多长的区间,能把所有数字变成一样 暴力枚举每一种长度, 主要就是check该长度下是否合法的写法问题

/** @Date    : 2017-09-14 19:52:52
  * @FileName: I 枚举 暴力.cpp
  * @Platform: Windows
  * @Author  : Lweleth (SoungEarlf@gmail.com)
  * @Link    : https://github.com/
  * @Version : $Id$
  */
#include <bits/stdc++.h>
#define LL long long
#define PII pair<int ,int>
#define MP(x, y) make_pair((x),(y))
#define fi first
#define se second
#define PB(x) push_back((x))
#define MMG(x) memset((x), -1,sizeof(x))
#define MMF(x) memset((x),0,sizeof(x))
#define MMI(x) memset((x), INF, sizeof(x))
using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 1e5+20;
const double eps = 1e-8;


char s[500];

int check(int k)
{
	int len = strlen(s + 1);
	int q[500];
	for(int i = 0; i < 10; i++)
	{
		MMF(q);
		int cnt = 0;
		int flag = 0;
		for(int j = 1; j <= len; j++)
		{
			if(j > k)
				cnt = (cnt - q[j - k] + 10) % 10;
			if((q[j] + s[j] - '0' + cnt) % 10 != i && j + k - 1 > len)
			{
				flag = 1;
				break;
			}
			q[j] = (i - (q[j] + 10 + s[j] - '0' + cnt)%10 + 10) % 10;
			cnt = (cnt + q[j]) % 10;
			//cout << i<<j<< k<<endl;
		}
		if(!flag)
			return 1;
	}
	return 0;
}
int main()
{
	int T;
	cin >> T;
	while(T--)
	{
		scanf("%s", s + 1);
		int x = strlen(s + 1);
		int ans = 1;
		for(int i = x; i >= 1; i--)
		{
			if(check(i))
			{
				ans = i;
				break;
			}
		}
		printf("%d\n", ans);
	}
    return 0;
}

J 贪心 离散化大小,存数量,排序,从前往后比较,如果一种糖果不够分,只能用下一种糖果,且下个年龄也要从下种糖果开始枚举

 /** @Date    : 2017-09-01 15:59:40
  * @FileName: D.cpp
  * @Platform: Windows
  * @Author  : Lweleth (SoungEarlf@gmail.com)
  * @Link    : https://github.com/
  * @Version : $Id$
  */
#include <bits/stdc++.h>
#define LL long long
#define PII pair
#define MP(x, y) make_pair((x),(y))
#define fi first
#define se second
#define PB(x) push_back((x))
#define MMG(x) memset((x), -1,sizeof(x))
#define MMF(x) memset((x),0,sizeof(x))
#define MMI(x) memset((x), INF, sizeof(x))
using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 1e5+20;
const double eps = 1e-8;

int vis[1010][1010];
int dp[1010];
char a[1010];
int n, k;

int main()
{
	int T;
	cin >> T;
	while(T--)
	{
		scanf("%d%d", &n, &k);
		scanf("%s", a + 1);
		MMF(vis);
		for(int i = 1; i <= n; i++)
		{
			for(int j = i + 1; j <= n; j++)
			{
				if(a[j] == a[j - 1] || vis[i][j - 1])
					vis[i][j] = 1;
				else vis[i][j] = 0;
			}
			vis[i][i] = 1;
		}


		MMI(dp);
		dp[1] = 0;
		for(int i = 1; i < n; i++)
		{
			for(int j = 1; j <= k; j++)
			{
				if(j + i <= n && vis[i][i + j - 1])
					dp[i + j] = min(dp[i] + 1, dp[i + j]);
			}
		}
		int mi = INF;
		for(int i = n - k + 1; i <= n; i++)
		{
			if(vis[i][n])
				mi = min(mi, dp[i]);
		}
		printf("%d\n", mi);
	}
    return 0;
}

K 水 问k能不能由序列里不同下标的两个数相乘而得...

 /** @Date    : 2017-09-01 13:07:44
  * @FileName: K.cpp
  * @Platform: Windows
  * @Author  : Lweleth (SoungEarlf@gmail.com)
  * @Link    : https://github.com/
  * @Version : $Id$
  */
#include <bits/stdc++.h>
#define LL long long
#define PII pair<int ,int>
#define MP(x, y) make_pair((x),(y))
#define fi first
#define se second
#define PB(x) push_back((x))
#define MMG(x) memset((x), -1,sizeof(x))
#define MMF(x) memset((x),0,sizeof(x))
#define MMI(x) memset((x), INF, sizeof(x))
using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 1e5+20;
const double eps = 1e-8;

int vis[N];
int n, k;
int main()
{
	int T;
	cin >> T;
	while(T--)
	{
		scanf("%d%d", &n, &k);
		MMF(vis);

		for(int i = 0; i < n; i++)
		{
			int x;
			scanf("%d", &x);
			vis[x]++;
		}
		int ans = -1;
		for(int i = 1; i <= k; i++)
		{
			if(k % i == 0 && vis[i] && vis[k / i])
			{
				if(i == k / i && vis[i] < 2)
					continue;
				ans = i;
				break;
			}
		}
		if(ans > 0)
			printf("%d %d\n", ans, k / ans);
		else printf("-1\n");
	}
    return 0;
}

L D题的加强版,普通O n^2不能满足,考虑使用单调队列优化DP

 

posted @ 2017-09-02 10:37  Lweleth  阅读(268)  评论(0编辑  收藏  举报