2016-2017 ACM-ICPC, NEERC, Central Subregional Contest.

LINK

A. Fried Fish

思路

  • 注意 n < = k n <= k n<=k 的时候答案是 2 2 2
AC(ez)
#include <bits/stdc++.h>
using namespace std;
int main(){
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
	int n, k;
	cin >> n >> k;
	if (n <= k) cout << 2 << endl; 
	else if (n * 2 % k) cout << 2 * n / k + 1 << endl;
	else cout << 2 * n / k << endl;
	return 0;
}

B. Hanoi tower

思路

根据之前的汉诺塔模型推断就可以,原来的汉诺塔模型是 2 n − 1 2^n - 1 2n1
如果输入是 3 n 3n 3n
如果 n n n 是奇数: 2 2 n − 1 + 2 n − 2 2^{2n-1}+2^n-2 22n1+2n2
如果 n n n 是偶数: 2 2 n − 1 + 2 n − 1 − 1 2^{2n-1} + 2^{n-1} - 1 22n1+2n11

AC(高精度 + 递归)
#include <bits/stdc++.h>
using namespace std;
const int N = 1e4 + 10;
int ans[N], par1[N], par2[N];
int main(){
	freopen("input.txt", "r", stdin);
	freopen("output.txt", "w", stdout);
	int n;
	cin >> n;
	n /= 3;
	par1[1] = par2[1] = 1;
	int len1 = 1, len2 = 1;
	for (int i = 1; i <= n; i ++ ) {
		for (int j = 1; j <= len1; j ++ )
			par1[j] *= 2;
		for (int j = 1; j <= len1; j ++ ) {
			par1[j + 1] += par1[j] / 10;
			par1[j] %= 10;
		}
		while (par1[len1 + 1]) {
			len1 ++;
			par1[len1 + 1] += par1[len1] / 10;
			par1[len1] %= 10;
		}
	}
	for (int i = 1; i < n; i ++ ) {
		for (int j = 1; j <= len2; j ++ )
			par2[j] *= 2;
		for (int j = 1; j <= len2; j ++ ) {
			par2[j + 1] += par2[j] / 10;
			par2[j] %= 10; 
		}
		while (par2[len2 + 1]) {
			len2 ++;
			par2[len2 + 1] += par2[len2] / 10;
			par2[len2] %= 10;
		}
	}
	for (int i = 1; i <= len1; i ++ ) 
		for (int j = 1; j <= len2; j ++ ) 
			ans[i + j - 1] += par1[i] * par2[j];
	for (int i = 1; i <= len1 + len2 - 1; i ++ ) {
		ans[i + 1] += ans[i] / 10;
		ans[i] %= 10;
	}
	int len = len1 + len2 - 1;
	while (ans[len + 1]) {
		len ++;
		ans[len + 1] += ans[len] / 10;
		ans[len] %= 10;
	}
	if (n & 1) {
		for (int i = 1; i <= len1; i ++ ) 
			ans[i] += par1[i];
		for (int i = 1; i <= len; i ++ ) {
			ans[i + 1] += ans[i] / 10;
			ans[i] %= 10; 
		}
		while (ans[len + 1]) {
			len ++;
			ans[len + 1] += ans[len] / 10;
			ans[len] %= 10;
		}
		ans[1] -= 2;
		if (ans[1] < 0) {
			int k = 1;
			while (k <= len && ans[k] < 0) {
				ans[k] += 10;
				ans[k + 1] --;
				k ++;
			}
			if (k == len && ans[k] == 0) len --;
		}
	} else {
		for (int i = 1; i <= len2; i ++ ) 
			ans[i] += par2[i];
		for (int i = 1; i <= len; i ++ ) {
			ans[i + 1] += ans[i] / 10;
			ans[i] %= 10; 
		}
		while (ans[len + 1]) {
			len ++;
			ans[len + 1] += ans[len] / 10;
			ans[len] %= 10;
		}
		ans[1] --;
		if (ans[1] < 0) {
			int k = 1;
			while (k <= len && ans[k] < 0) {
				ans[k] += 10;
				ans[k + 1] --;
				k ++;
			}
			if (k == len && ans[k] == 0) len --;
		}
	}
	for (int i = len; i >= 1; i -- ) cout << ans[i];
	cout << endl;
	return 0;
}

D. Weather Station

思路

  • 快速幂
AC(ez)
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int mod = 1e9 + 7;
LL qmi(int a, int q) {
	LL tmp = a;
	LL ans = 1;
	while (q) {
		if (q & 1) ans = ans * tmp % mod;
		tmp = tmp * tmp % mod;
		q >>= 1;
	}
	return ans;
}
int main(){
	freopen("input.txt", "r", stdin);
	freopen("output.txt", "w", stdout);
	string s;
	cin >> s;
	int len = s.size();
	int q = 0;
	for (int i = 1; i < len; i ++ ) {
		if (s[i] == 'E' && (s[i - 1] == 'N' || s[i - 1] == 'S')) q ++;
		if (s[i] == 'W' && (s[i - 1] == 'N' || s[i - 1] == 'S')) q ++;
	}
	cout << qmi(2, q);
	return 0;
}

E. Cupcakes

思路

  • 挺简单的, 就是模拟一遍就能过
  • p r e m n premn premn 就是在某论贪心的同学之前所有同学吃的最小值
  • p r e m x premx premx 就是在某论贪心的同学之前所有同学吃的最大值
  • p o s pos pos 就是贪心同学的位置
  • m x mx mx 就是贪心的同学的 a [ i ] a[i] a[i]
  • s u m sum sum 储存一轮除了贪心的同学, 剩下同学吃的最大值

细节注释

  • 注释1:为什么是 k − = m x k -= mx k=mx 因为贪心的同学遇到蛋糕就是全吃, 所以如果这轮不能结束游戏, 那么贪心的同学会全部吃完, 把 k k k 卡在 p r e m n premn premn p r e m x premx premx 之间, 就是看, 以这两种极端的情况为标准, 判断能不能, 让除了被贪心同学吃的蛋糕, 被剩下的同学分完
AC(模拟)
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
int a[N];
int main(){
	freopen("INPUT.TXT", "r", stdin);
	freopen("OUTPUT.TXT", "w", stdout);
	int n, k;
	scanf("%d%d", &n, &k);
	int pos, mx = 0;
	LL sum = 0;
	for (int i = 1; i <= n; i ++ ) {
		scanf("%d", a + i);
		if (a[i] > mx) {
			pos = i;
			mx = a[i];
		}
		sum += a[i];
	}
	sum -= mx;
	LL premn = pos - 1, premx = 0;
	for (int i = 1; i < pos; i ++ ) 
		premx += a[i];
	while (k >= 0) {
		if (k >= premn && k <= premx) { //注释1
			puts("YES");
			return 0;
		}
		k -= mx; //注释1
		premn += n - 1;
		premx += sum;
	}
	puts("KEK");
	return 0;
}

F. Vitamins

思路

  • 按并查集分类就可以了, 然后就是按照是否为 R R R 判断, 并将祖宗节点染色, 染色之对于子节点也要染色

细节注释

  • 注释1:为什么 = = = 要提前操作, 因为只有 = = = 提前操作就可以把点之间的相同颜色的点就可以归为一类了, 这样子不会影响出现在 = = = 号前面的 < < < > > > , 就可以充分归类了
  • 注释2:如果 b i g big big s m a l l small small 都不为空, 证明了该节点就是 R R R, 然后依次取出在 b i g big big s m a l l small small 中储存的祖宗节点染色
  • 注释3:把没有染色完全的子节点依次染色, 注意是 f i n d ( p [ i ] ) find(p[i]) find(p[i]), 要找祖宗节点, 不可以只写 p [ i ] p[i] p[i]

总结

  • 以后并查集一定要写 f i n d ( p [ i ] ) find(p[i]) find(p[i]), 不可以对 p [ i ] p[i] p[i] 掉以轻心, 因为可能存在根本没有把之后的子节点接到最终的祖宗节点上
AC(并查集)
#include <bits/stdc++.h>
using namespace std;
#define PB push_back
typedef vector<int> VI;
const int N = 1e3 + 10;
int p[N], a[N * N / 2], b[N * N / 2];
char op[N * N / 2], ans[N];
VI big[N], small[N];
int find(int x) {
	if (p[x] == x) return x;
	return p[x] = find(p[x]);
}
int main(){
	freopen("INPUT.TXT", "r", stdin);
	freopen("OUTPUT.TXT", "w", stdout);
	int n, m;
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i ++ ) 
		p[i] = i, ans[i] = '?';
	for (int i = 1; i <= m; i ++ ) {
		scanf("%d%c%d", &a[i], &op[i], &b[i]);
		if (op[i] == '=') //注释1
			p[find(a[i])] = find(b[i]);
	}
	for (int i = 1; i <= m; i ++ ) {
		if (op[i] == '<') {
			big[find(a[i])].PB(find(b[i]));
			small[find(b[i])].PB(find(a[i]));
		} else if (op[i] == '>'){
			big[find(b[i])].PB(find(a[i]));
			small[find(a[i])].PB(find(b[i]));
		}
	}
	for (int i = 1; i <= n; i ++ ) {
		if (big[i].size() > 0 && small[i].size() > 0) { //注释2
			ans[i] = 'R';
			for (auto t : big[i]) 
				ans[t] = 'W';
			for (auto t : small[i])
				ans[t] = 'B';
		}
	}
	for (int i = 1; i <= n; i ++ ) {
		if (ans[i] == '?') 
			ans[i] = ans[find(p[i])]; //注释3
	}
	for (int i = 1; i <= n; i ++ ) 
		printf("%c", ans[i]);
	puts("");
	return 0;
}

G. Sphenic numbers

思路

  • 质数唯一分解定理
AC(ez)
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int ans[N];
int main(){
	freopen("input.txt", "r", stdin);
	freopen("output.txt", "w", stdout);
	int n, cnt = 0;
	cin >> n;
	for (int i = 2; i <= n; i ++ ) {
		while (n % i == 0) {
			ans[cnt ++] = i;
			n /= i;
		}
	}
	if (cnt == 3) {
		if (ans[1] != ans[2] && ans[1] != ans[0]) cout << "YES" << endl;
		else cout << "NO" << endl;
	} else cout << "NO" << endl;
	return 0;
}

H. Non-random numbers

思路

  • 我们发现只要是大于 9 9 9 的数字就是在 9 9 9 之后补 0 0 0, 因为他只卡前 9 9 9 位, 那么前 9 9 9 个数字就是暴力跑一遍, 直接打表就好
AC(math)
#include <bits/stdc++.h>
using namespace std;
LL ans[10] = {0, 8, 72, 648, 5832, 52488, 472392, 4251528, 38263752, 344373768};
int main(){
	freopen("input.txt", "r", stdin);
	freopen("output.txt", "w", stdout);
	int n;
	cin >> n;
	if (n <= 9) cout << ans[n];
	else {
		cout << ans[9];
		n -= 9;
		while (n --) 
			cout << 0;
	}
	return 0;
}

J. Architect of Your Own Fortune

思路

AC(二分图)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
int mat[105][105];
int at[105][105],ta[105][105];
struct node{
	int pre,beh;
}a[105],b[105];
int n,m;
string s1[105],s2[105];
bool vis[N];
int ans[N];
bool dfs(int x){
	for(int i=1;i<=m;i++){
		if(!vis[i]&&mat[x][i]){
			vis[i]=1;
			if(!ans[i]||dfs(ans[i])){
				ans[i]=x;
				return true;
			}
		}
	}
	return false;
}
int main(){
	freopen("input.txt", "r", stdin);
	freopen("output.txt", "w", stdout);
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>s1[i];
		a[i].pre =s1[i][0]-'0'+s1[i][1]-'0'+s1[i][2]-'0';
		a[i].beh =s1[i][3]-'0'+s1[i][4]-'0'+s1[i][5]-'0';
	}
	for(int i=1;i<=m;i++){
		cin>>s2[i];
		b[i].pre =s2[i][0]-'0'+s2[i][1]-'0'+s2[i][2]-'0';
		b[i].beh =s2[i][3]-'0'+s2[i][4]-'0'+s2[i][5]-'0';
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(a[i].pre ==b[j].beh ){
				mat[i][j]=1;
				at[i][j]=1;
			}
			if(a[i].beh ==b[j].pre ){
				mat[i][j]=1;
				ta[i][j]=1;
			}	
		}
	}
	int cnt=0;
	for(int i=1;i<=n;i++){
		memset(vis,0,sizeof(vis));
		if(dfs(i))
			cnt++;
	}
	cout<<cnt<<endl;
	for(int i=1;i<=m;i++){
		if(ans[i]!=0){
			int t=ans[i];
			if(at[t][i]==1){
				cout<<"AT"<<" ";
				cout<<s1[t]<<" "<<s2[i]<<endl;
			}
			else if(ta[t][i]==1){
				cout<<"TA"<<" ";
				cout<<s2[i]<<" "<<s1[t]<<endl;
			}
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值