Codeforces Round #824 (Div. 2) CD

C. Phase Shift

题意:给定一个长度为 n n n的密文,要你求原串。解密规则:26个小写英文字母以某种顺序排成一个圆圈,对于密文的每个字母,原字母是圆圈的下一个字母(顺时针)。
思路:遍历密文的每个字母,如果该字母未在之前找到匹配字母,则贪心选择最小的 可用的(不会形成大小小于26的圆圈)的字母,作为该字母的匹配字母。如何判断可用的?可以check模拟一下是否会成大小小于26的圆圈(详细看代码)。
代码:

#include <bits/stdc++.h>
using namespace std;

#define int long long
int T,n;
string s;
bool vis[26];
map<char,char> mp;

bool check(char a,char c){
	while(mp.find(c)!=mp.end()){
		if(mp[c]==a) return false;
		c=mp[c];
	}
	return true;
}

signed main(){
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	cin>>T;
	while(T--){
		for(int i=0;i<26;++i) vis[i]=false;
		mp.clear();
		cin>>n>>s;
		string t="";
		for(int i=0;i<s.size();++i){ 
			if(mp.find(s[i])==mp.end()){
				for(int j=0;j<26;++j){
					if(vis[j]==false && (char)(j+'a')!=s[i]){
						if(check(s[i],(char)(j+'a')) || mp.size()==25) {
							mp[s[i]]=(char)(j+'a');
							vis[j]=true;
							break;
						}
					}
				}
			}
			t+=mp[s[i]];
		}
		cout<<t<<'\n';
	}
}

D. Meta-set

题意:给定 n n n张牌,每张牌有 k k k种属性(每种属性取值为0,1,2),保证给定的两张牌不会所有属性都一样。定义一个好的三元组为:三张牌的每个属性要么都一样,要么两两互不相同。定义一个meta-set五元集为五元集里至少存在两个好的三元组。求 n n n张牌里有多少个五元集。
思路:官方题解讲得非常好非常好!!!建议看官方题解
代码:

#include <bits/stdc++.h>
using namespace std;

#define int long long
#define pii pair<int,int> 
#define pb push_back
#define fi first
#define se second
const int N=1e3+3;
int T,n,m;
string s[N];
map<string,int> mp;
vector<pii> v[N];
 
signed main(){
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
//	cin>>T;
	T=1;
	while(T--){
		cin>>n>>m;
		string t="";
		int tt;
		for(int i=1;i<=n;++i){
			t="";
			for(int j=1;j<=m;++j){
				cin>>tt;
				t+=(char)(tt+'0');
			}
			s[i]=t;
			mp[t]=i;
		}
		for(int i=1;i<=n;++i){
			for(int j=1;j<=n;++j) {
				if(i==j) continue;
				t="";
				for(int k=0;k<m;++k) {
					if(s[i][k]==s[j][k]) t+=s[i][k];
					else {
						if(s[i][k]!='0' && s[j][k]!='0') t+='0';
						else if(s[i][k]!='1' && s[j][k]!='1') t+='1';
						else t+='2';
					}
				}
				if(mp.find(t)!=mp.end() && mp[t]!=i && mp[t]>j) //大于是为了避免重复放同一种集合 
					v[i].pb({j,mp[t]});
			}
		}
		int ans=0;
		for(int i=1;i<=n;++i){
			if(v[i].size()) ans+=(v[i].size()-1+1)*(v[i].size()-1)/2;
		}
		cout<<ans<<'\n';
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值