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';
}
}