AtCoder Beginner Contest 371 题解 ABCDE

Problem A:

题意:给定三个人AB,AC,BC的大小相对关系,输出在中间的那个,保证不存在重复的

思路:比较明显的模拟

char s[3];
	cin >> s[0] >> s[1]>>s[2];
	if(s[0]=='>'){
		if(s[1]=='>'){
			if(s[2]=='>'){// >>>
				cout <<"B"<<endl;
			}
			else{//>><
				cout << "C"<<endl;
			}
		}
		//><>不存在
		else{//><<
			cout <<"A"<<endl;
		}
	}
	else{
		if(s[1]=='>'){//<>
			if(s[2]=='>'){//<>>
				cout <<"A"<<endl;
			}
		}
		else{
			if(s[2]=='>'){
				cout <<"C"<<endl;
			}
			else{
				cout <<"B"<<endl;
			}
			
		}
	}

Problem B:

题意:给点N个家族和M个查询,每个查询给定一个家族名字和性别,判断是不是这个家族第一次出现性别为男的

思路:对于每个家族记录有没有第一次出现即可

int n , m;cin >> n >> m;
	map<int,bool> mp;
	while(m--){
		int x;char op;
		cin >> x >> op;
		if(op == 'M'){
			if(!mp[x]){
				mp[x] = true;
				cout <<"Yes\n";
			}
			else{
				cout <<"No\n";
			}
		}
		else cout <<"No\n";
	}

problem C:

题意:给定两个无向图,图G为目标图,图H为操作图,你需要进行操作添加或删除边 (次数可以为0),使得两个图同构,每个添加或者删除耗费V(i,j)个价值,输出最小耗费价值。

思路:

首先要了解图的同构:两个图顶点数相同,边数相同,每个点度数相同,邻接关系相同。

观察到数据范围N<=8,因此可以将图的所有可能的顶点排列,计算每种排列的转换成本,并找出最小的成本即可

void dfs(int u){
	if(u == n + 1)
	{
		int ans = 0;
		for(int i = 1; i <= n; i++){
			for(int j = 1; j <= n; j++){
				if(e1[i][j] != e2[num[i]][num[j]]){
					ans += w[i][j];
				}
			}
		}
		minn = min(minn, ans);
		return ;
	}
	for(int i = 1; i <= n; i++){
		if(vis[i]) continue;
		vis[i] = 1;
		num[u] = i;
		dfs(u + 1);
		vis[i] = 0;
		num[u] = 0;
		//枚举
	}
}
int32_t main(){
	cin >> n;
	cin >> m2;
	for(int i = 1; i <= m2; i++){
		int x, y;
		cin >> x >> y;
		e2[x][y] = e2[y][x] = 1;
	}
	cin >> m1;
	for(int i = 1; i <= m1; i++){
		int x, y;
		cin >> x >> y;
		e1[x][y] = e1[y][x] = 1;
	}
	for(int i = 1; i < n; i++) for(int j = i + 1; j <= n; j++) cin >> w[i][j];
	dfs(1);
	cout << minn << endl;
	return 0;
}

problem D:

题意:在一条线上有N个村庄,其中第i个村庄位于X_i处有P_i个村民,有Q个查询,每次给定L,R输出L,R之间(含)村庄的村民总数

| X_i,P_i | <= 1e9 ,N<=2e5

思路:观察到数据很稀疏,可以使用离散化+前缀和,查询的时候使用二分

cin >> n;	
	VI x;
	VI p;
	for (int i = 0; i < n; i++) {
		int xx;
		cin >> xx;
		x.push_back(xx);
	}
	for (int i = 0; i < n; i++) {
		int pp;
		cin >> pp;
		p.push_back(pp);
	}
	for (int i = 0; i < n; ++i) {
		s[i + 1] = s[i] + p[i];
	}
	cin >> q;
	while (q--) {
		int L, R;
		cin >> L >> R;
		
		VI::iterator itl = lower_bound(x.begin(), x.end(), L);
		VI::iterator itr = upper_bound(x.begin(), x.end(), R);
		
		int l = distance(x.begin(), itl);
		int r = distance(x.begin(), itr) - 1;
		
		if (l <= r && l < n && r >= 0) {
			LL ans = s[r + 1] - s[l];
			cout << ans <<endl;
		} else {
			cout << 0 << endl;
		}
	}

problem E:

题意:给定一个长度为 n的数组 a,定义函数f(i,j)表示区间 (al,al+1,…ar)中不同值的个数

求:\sum_{i=1}^{N}\sum_{j=i}^{N} f(i,j),数据范围2e5

思路:翻译过来就是:求每个子区间内含有的不同数字的个数之和

考虑枚举右端点,记last_i为 i这个数最后出现的位置,每次在右边插入一个数,实时更新对前面最有左端点的影响,可以发现对1-last_i的位置没有影响,而对last_i + 1到当前位置有影响,统计答案并更新last_i即可

cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	for(int i=1;i<=n;i++){
		sum+=i-lst[a[i]];
		lst[a[i]]=i;
		ans+=sum;
	}
	cout<<ans;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值