牛客多校第八场

K-Kabaleo Lite

题意及思路

第一个难点就是对原本两个数组的处理,一个是前缀和,一个使其递减
第二个难点是long long会爆精度,写不好__in128,我选择用两个数存储高位和低位。
在这里插入图片描述

插一句,函数返回值一定不要写错,否则会段错误。。。

代码(wrong,只能过75%数据,有空再挣扎一下。。。)

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
const long long MOD = 1e14;

long long a[N], p[N], b[N], num[N];

int solve(int len) {
	num[0] = b[0];
	p[0] = a[0];
	int k = 1;
	for(int i = 1; i < len; i++) {
		b[i] = min(b[i],b[i-1]);
		if(a[i] > 0) {
			p[k] = a[i];
			num[k] = b[i];
			k++;
		}
		else {
			a[i+1] += a[i];	
		}
	}
	return k;
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n,t;
	cin>>t;
	for(int i = 1; i <= t; i++) {
		memset(num,0,sizeof(num));
		memset(p,0,sizeof(p));
		cin>>n;
		long long ans = 0,temp = 0;
		for(int j = 0; j < n; j++) {
			cin>>a[j];
		}
		for(int j = 0; j < n; j++) {
			cin>>b[j];
		}
		int l = solve(n);
		 
		for(int j = 0; j < l; j++) {
			temp += p[j]*num[j];
			ans += temp/MOD;
			temp %= MOD;
		}
		printf("Case #%d: %lld ",i,b[0]);
		if(ans) printf("%lld%014lld\n",ans,abs(temp));
		else	printf("%lld\n",temp);
		//cout<<ans<<endl;
	}
	return 0;
}

代码(AC)

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
const long long MOD = 1e14;

long long a[N], p[N], b[N];

void solve(int n) {
	p[0] = a[0];
	for(int i = 1; i < n; i++) {
		b[i] = min(b[i],b[i-1]);
		p[i] = a[i] + p[i-1];
	}
	int p1 = 0, p2 = 0;
	long long ans = 0, gw = 0;
	ans = p[0] * b[0];
	while(p2 < n) {
		while(p2 < n && p[p2] <= p[p1]) 
			p2++;
		if(p2 == n) break;
		ans +=b[p2] * (p[p2] - p[p1]);
		gw += ans/MOD;
		ans %= MOD;
		p1 = p2;
	}
	if(gw) printf("%lld%014lld\n",gw,ans);
	else	printf("%lld\n",ans);
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n,t;
	cin>>t;
	for(int i = 1; i <= t; i++) {
		memset(a,0,sizeof(a));
		memset(b,0,sizeof(b));
		memset(p,0,sizeof(p));
		cin>>n;
		for(int j = 0; j < n; j++) {
			cin>>a[j];
		}
		for(int j = 0; j < n; j++) {
			cin>>b[j];
		}
		printf("Case #%d: %lld ",i,b[0]);
		solve(n);
		//cout<<ans<<endl;
	}
	return 0;
}

I -Interesting Computer Game

题意及思路

题目:给定N,一共N轮,每一轮给定两个数,每次只能选择一个数,要求最后经过N轮选择数的数量达到最大。
第一步:对于每一轮输入的两个数,都需要标记是否出现过,可以用一个map做离散化,key作为这个数值,value作为标记,比用二维数组节省了很多空间
第二步:用并查集,主要就是两个函数,find()查找父节点,merge()使两个点的父节点一致,同时再使用一个数组标记是否出现了环,例如【1,2】,【3,2】,【1,3】,出现了则标记2(他们的父节点),当一个点作为父节点(即fa[i] = i),即删去这个点,仅有当出现环(c[i] = 1),则不做处理,保留。

代码

注意父节点数组要开到两倍大小,否则会越界,还有判别数组c数组

#include<bits/stdc++.h> 
using namespace std;
const int N = 1e5 + 5;

map<int,int> q;
int a[N],b[N],fa[2*N],c[2*N];

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

void merge(int x,int y) {
	int fx = find(x);
	int fy = find(y);
	if(fx != fy) {
		fa[fx] = fy;
		if(c[fx] != 0 || c[fy] != 0)  {
			//cout<<'a'<<endl;
			c[fy] = 1, c[fx] = 0;
		}
		return;
	}
	//cout<<"a"<<endl;
	c[fy] = 1;
	return;
}

int main() {
	int n,t;
	scanf("%d",&t);
	for(int j = 1; j <= t; j++) {
		scanf("%d",&n);
		int k = 0;
		q.clear();
		for(int i = 0; i < n; i++) {
			scanf("%d %d",&a[i],&b[i]);
			if(!q[a[i]]) q[a[i]] = ++k;
			if(!q[b[i]]) q[b[i]] = ++k;
		}
		fill(c+1,c+k+1,0);
		for(int i = 1; i <= k; i++)  fa[i] = i;
		for(int i = 0; i < n; i++) {
			merge(q[a[i]], q[b[i]]);
		}
		int ans = k;
		for(int i = 1; i <= k; i++)
			if(fa[i] == i && !c[i]) 
				ans--;
		printf("Case #%d: %d\n",j,ans);
	}
	return 0;
}

Game SET

题意及分析

暴力乱搞一搞就过了,因为n很小所以不用担心时间复杂度,因为集合没清零,卡了三次错才发现,保留的注释可以输出每个属性用来测试数据哪里出错挺好的。

代码

#include<bits/stdc++.h> 
using namespace std;
const int N = 300;
string s[N][5];
set<string> q[4];

inline string read() {
	string q;
	char ch = getchar();
	while((ch < 'a' || ch > 'z') && ch != '*') {
		ch = getchar();
	}
	while((ch >= 'a' && ch <= 'z') || ch == '*') {
		q += ch;
		ch = getchar();
	}
	return q;
}

bool solve(int i, int j, int k, int t) {
	q[i].insert(s[j][i]);
	q[i].insert(s[k][i]);
	q[i].insert(s[t][i]);
	/*for(auto it = q[i].begin();it != q[i].end(); it++)
		cout<<*it<<" ";
	cout<<endl;*/
	if(q[i].size() == 2 && q[i].find("*") == q[i].end())
		return false;
	return true;
}

int main() {
	int t,n;
	scanf("%d",&t);
	for(int j = 1; j <= t; j++) {
		scanf("%d",&n);
		for(int i = 0; i < n; i++) {
			s[i][0] = read();
			s[i][1] = read();
			s[i][2] = read();
			s[i][3] = read();
		}
		/*for(int i = 0; i < n; i++) {
			cout<<s[i][0]<<" ";
			cout<<s[i][1]<<" ";
			cout<<s[i][2]<<" ";
			cout<<s[i][3]<<endl;
		}*/
		int f = 0;
		for(int i = 0; i < n-2; i++) {

			for(int k = i+1; k < n-1; k++) {

				for(int m = k+1; m < n; m++) {
					for(int p = 0;p < 4; p ++)
						q[p].clear();
					bool f0 = solve(0,i,k,m);
					bool f1 = solve(1,i,k,m);
					bool f2 = solve(2,i,k,m);
					bool f3 = solve(3,i,k,m);
					if(f1&f2&f3&f0)	{
						f = 1;
						printf("Case #%d: %d %d %d\n",j,i+1,k+1,m+1);
						break;
					}
					else	continue;
				}
				if(f == 1)	break;
			}
			if(f == 1)	break;
		}
		if(!f)	printf("Case #%d: -1\n",j);		
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值