2017-2018 ACM-ICPC East Central North America Regional Contest (ECNA 2017) 部分题解

contest 链接:http://codeforces.com/gym/101673

 

A - Abstract Art

求多个多边形并的面积,板子题,记小本本

#include
using namespace std;
#define mp make_pair
typedef long long ll;
const double inf=1e200;
const double eps=1e-12;
const double pi=4*atan(1.0);
int dcmp(double x){ return fabs(x)p){
    double ans=0; int sz=p.size();
    for(int i=1;ipp[110];
pairs[110*60];
double polyunion(vector*p,int N){
    double res=0;
    for(int i=0;i=0&&c2<0) s[m++]=mp(s1/(s1-s2),1);
                            else if(c1<0&&c2>=0) s[m++]=mp(s1/(s1-s2),-1);
                        }
                    }
                }    
            }
            sort(s,s+m);
            double pre=min(max(s[0].first,0.0),1.0),now,sum=0;
            int cov=s[0].second;
            for(int j=1;j

 

C - DRM Messages

很水的小模拟

在不知道题意的情况下听队友说步骤就过了

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define fi first
#define se second
#define pb push_back
#define lowbit(x) x&(-x)
#define PII  pair 
#define all(x) x.begin(), x.end()
#define FAST ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int mod = (int)1e9 + 7;
const int maxn = (int)1e3 + 5;
using namespace std;

int main()
{
	string s;
	cin >> s;
	int len = s.size();
	int sum = 0;
	for(int i = 0; i < len / 2; i++){
		sum += s[i] - 'A';
	}
	for(int i = 0; i < len / 2; i++){
		s[i] = (s[i] - 'A' + sum) % 26 + 'A';
	}
	sum = 0;
	for(int i = len / 2; i < len; i++){
		sum += s[i] - 'A';
	}
	for(int i = len / 2; i < len; i++){
		s[i] = (s[i] - 'A' + sum) % 26 + 'A';
	}
	for(int i = 0; i < len / 2; i++){
		s[i] = (s[i] - 'A' + s[i+len/2] - 'A') % 26 + 'A';
	}
	for(int i = 0; i < len / 2; i++){
		cout << s[i];
	}
	cout << endl;
	return 0;
}

 

D - Game of Throwns

这也是个水题啊,用栈模拟一下就好了

但还是因为取模没考虑负数WA了两发

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define fi first
#define se second
#define pb push_back
#define lowbit(x) x&(-x)
#define PII  pair 
#define all(x) x.begin(), x.end()
#define FAST ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int mod = (int)1e9 + 7;
const int maxn = (int)1e3 + 5;
using namespace std;

stack st;

int main()
{
	int n, k;
	cin >> n >> k;
	for(int i = 1; i <= k; i++){
		string s; cin >> s;
		if(s == "undo"){
			int cnt;
			cin >> cnt;
			while(cnt--){
				st.pop();
			}
		}
		else{
			stringstream ss;
			ss << s;
			int x;
			ss >> x;
			st.push(x);
		}
	}
	int ans = 0;
	while(!st.empty()){
		ans += st.top();
		st.pop();
	}
	cout << (ans + 3000 * n) % n << endl;
}

 

H - Sheba's Amoebas

题意:求出黑色环的个数, 数据保证不相交

解题思路:其实也就是个简单的dfs,因为要判断环,多开一个vis数组标记一下即可

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define fi first
#define se second
#define pb push_back
#define lowbit(x) x&(-x)
#define PII  pair 
#define all(x) x.begin(), x.end()
#define FAST ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int mod = (int)1e9 + 7;
const int maxn = (int)1e3 + 5;
using namespace std;

char G[110][110];
int dir[8][2] = { {1, 0}, {0, 1}, {-1, 0}, {0, -1}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1} };
bool vis1[110][110], vis2[110][110];
int n, m;
int startx, starty;
int ans;

bool check(int x, int y){
	if(x >= 1 && x <= n & y >= 1 && y <= m && G[x][y] == '#' && !vis1[x][y] & ! vis2[x][y]) return true;
	return false;
}

void dfs(int x, int y, int cnt){
	bool flag = false;
	for(int i = 0; i <= 7; i++){
		int tx = x + dir[i][0], ty = y + dir[i][1];
		if(check(tx, ty)){
			vis1[tx][ty] = vis2[tx][ty] = 1;
			dfs(tx, ty, cnt + 1);
			vis1[tx][ty] = 0;
			flag = true;
		}
	}
	if(!flag && cnt > 1)
		for(int i = 0; i <= 7; i++){
			int tx = x + dir[i][0], ty = y + dir[i][1];
			if(tx == startx && ty == starty){
				ans++;
				return;
			}
		}
}
int main()
{
	scanf("%d %d", &n, &m);
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= m; j++){
			scanf(" %c", &G[i][j]);
		}
	}
	ans = 0;
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= m; j++){
			if(!vis1[i][j] && G[i][j] == '#'){
				memset(vis1, 0, sizeof(vis1));
				vis1[i][j] = vis2[i][j] =  true;
				startx = i, starty = j;
				dfs(i, j, 1);
			}
		}
	}
	printf("%d\n", ans);
	return 0;
}

 

好啦,无脑题都说完啦

G - A Question of Ingestion

题目大意:一开始的食量为m,有n个连续的小时,每小时都有一个a[i]表示,可以选择吃或者不吃。

这个小时吃的话下个小时的食量就变成2/3,上个小时吃了这个小时不吃的话下个小时恢复到上个小时的,连续两小时不吃就能恢复到m

解题思路:开始题意理解错了,这么简单的一个记忆化搜索都没做出来,伤心。。

直接记忆化搜索枚举不吃的小时即可

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define fi first
#define se second
#define pb push_back
#define lowbit(x) x&(-x)
#define PII  pair 
#define all(x) x.begin(), x.end()
#define FAST ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int mod = (int)1e9 + 7;
const int maxn = (int)1e5 + 5;
using namespace std;

int a[105];
int dp[105][20005];
int n, m;

int dfs(int i, int j){
	if(i > n) return 0;
	if(dp[i][j] != -1) return dp[i][j];
	dp[i][j] = min(a[i], j) + max(dfs(i + 1, j * 2 / 3), max(dfs(i + 2, j), dfs(i + 3, m)));
	return dp[i][j];
}

int main()
{
	memset(dp, -1, sizeof(dp));
	scanf("%d %d", &n, &m);
	for(int i = 1; i <= n; i++){
		scanf("%d", a + i);
		a[i] = min(a[i], m);
	}
	int ans = 0;
	for(int i = 1; i <= n; i++){
		ans = max(ans, dfs(i, m));
	}
	printf("%d\n", ans);
	return 0;
}

还有一种dp写法:

dp[i][j] : 在第i个小时已经吃了j小时,获得的最大价值

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define fi first
#define se second
#define pb push_back
#define lowbit(x) x&(-x)
#define PII  pair 
#define all(x) x.begin(), x.end()
#define FAST ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int mod = (int)1e9 + 7;
const int maxn = (int)1e5 + 5;
using namespace std;

int n, m;
int a[105], val[105];
int dp[105][105];

int main()
{
	scanf("%d %d", &n, &m);
	for(int i = 1; i <= n; i++){
		scanf("%d", a + i);
	}
	val[1] = m;
	for(int i = 2; i <= n; i++){
		val[i] = val[i-1] * 2 / 3;
	}
	for(int i = 1; i <= n; i++){
		dp[i][1] = min(a[i], val[1]);
	}
	int ans = 0;
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= i; j++){
			if(i >= 1) dp[i][j] = max(dp[i][j], dp[i-1][j-1] + min(val[j], a[i]));
			if(i >= 2) dp[i][j] = max(dp[i][j], dp[i-2][j] + min(val[j], a[i]));
			if(i >= 3) dp[i][1] = max(dp[i][1], dp[i-3][j] + min(val[1], a[i]));
			ans = max(ans, dp[i][j]);
		}
		ans = max(ans, dp[i][1]);
	}
	printf("%d\n", ans);
	return 0;
}

Continuing...

================================================================================

update:

F - Keeping On Track

题目大意:给n条边,然后去掉一个影响最大的点(数据保证有且仅有一个),让你先求出当前没有联通的点的对数,再让你加一条边,求出加了之后最少的没有联通的点的对数。

解题思路:对于第一问,直接枚举删的点,维护最大值并且记录下来

对于第二问,肯定是把最大的两块合起来,一个dfs就可以解决了

身为一个菜鸡,这题妙处真的多,多说几句。

首先,很容易想到如果能够得到每一个节点作为根节点它的子树的大小,就很容易做出来了,但是这样的复杂度是n ^ 2的

那么这样考虑:边dfs边记录、更新答案。

用一个sz数组保存以0为根节点,每个点子树的大小。那么vector里面装它接下来子树的大小,那以前的怎么办呢?很巧妙的用了一个sum记录了dfs下去的和,那么n - sum就是之前的了。那么接下来,如何利用这个vector来判断不连通的点的对数呢?

比如有三个数:1, 2, 3

res = 2 * 1 + 3 * (1 + 2) = 11

验证一下: res = (1 * (2 + 3) + 2 * (1 + 3) + 3 * (1 + 2)) / 2 = 11

这个结论真的太妙了,知道了也就能理解怎么推出来的了

这样,我们只需要一个dfs就能求出枚举所有点被删除的情况了

我真是个图论小白

#pragma GCC diagnostic error "-std=c++11"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define fi first
#define se second
#define pb push_back
#define lowbit(x) x&(-x)
#define PII  pair 
#define all(x) x.begin(), x.end()
#define FAST ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int mod = (int)1e9 + 7;
const int maxn = (int)1e4 + 5;
using namespace std;
using __gnu_cxx::crope;

vector G[maxn];
int sz[maxn];
int n;
ll maxv = 0, id = 0;

void dfs(int u, int fa){
	sz[u] = 1;
	vector vec;
	int sum = 0;
	for(auto v : G[u]){
		if(v == fa) continue;
		dfs(v, u);
		vec.pb(sz[v]);
		sum += sz[v];
		sz[u] += sz[v];
	}
	vec.pb(n - sum);
	ll res = 0;
	ll ss = 0;
	for(auto i : vec){
		res += ss * i;
		ss += i;
	}
	if(res > maxv){
		maxv = res;
		id = u;
	}
}

void dfs2(int u, int fa){
	sz[u] = 1;
	for(int i = 0; i < G[u].size(); i++){
		int v = G[u][i];
		if(v == fa) continue;
		dfs2(v, u);
		sz[u] += sz[v];
	}
}

int main()
{
	FAST;
	cin >> n;
	for(int i = 1; i <= n; i++){
		int u, v; cin >> u >> v;
		G[u].pb(v);
		G[v].pb(u);
	}
	dfs(0, -1);
	dfs2(id, -1);
	vector vec;
	for(int i = 0; i < G[id].size(); i++) vec.pb(sz[G[id][i]]);
	if(vec.size() == 1) cout << 0 << ' ' << 0 << endl;
	else{
		sort(all(vec));
		vec[vec.size()-2] += vec[vec.size()-1];
		ll ss = 0, res = 0;
		for(int i = 0; i < vec.size() - 1; i++){
			res += ss * vec[i];
			ss += vec[i];
		}
		cout << maxv << ' ' << res << endl;
	}
	return 0;
}

Continuing...

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(codeforces,杂题解)