The 2021 ICPC Asia Shenyang Regional Contest (B/E/F/J)

题目链接:Dashboard - The 2021 ICPC Asia Shenyang Regional Contest - Codeforces

目录

E. Edward Gaming, the Champion

F. Encoded Strings I

J. Luggage Lock

B. Bitwise Exclusive-OR Sequence


E. Edward Gaming, the Champion

题意:给你一个字符串,问该字符串中有多少个“edgnb”。

思路:签到题,直接遍历一遍字符串统计数目即可。

代码: 

void solve() {
	cin>>s;
	int ans=0;
	for(int i=0; i<(int)s.size()-4; i++) {
		if(s[i]=='e'&&s[i+1]=='d'&&s[i+2]=='g'&&s[i+3]=='n'&&s[i+4]=='b')ans++;
	}
	cout<<ans<<endl;
}

F. Encoded Strings I

题意:给你一个字符串s,字符串中只包含英文小写字母,每个小写字母的映射方式为:

设该小写字母最后一个出现位置为i,字符串长度范围为1~n,x为s[i]~s[n]中不同字符的个数,则小写字母被映射为字母表中的第x个数(比如x=1,则映射为 ‘a’;x=2,则映射为 ‘b’)。

例如:字符串“aacc”会被映射为“bbaa”,而字符串“aca”会被映射为“aba”,

求解目标为长度1~n的前缀中字典序最小的映射后的字符串。

思路: 因为映射看的是每一个字母最后一个出现的位置,所以我们从后往前遍历字符串,得出每个字母的映射字母,最后暴力枚举得出每个前缀字符串的映射字符串,sort取字典序最小即可。

代码:

void solve() {
	map<char,char>mp;
	vector<string>v;
	int n;
	string s;
	cin>>n>>s;
	for(int i=0; i<n; i++) {
		map<char,char>mp;
		int cnt=0;
		string k;
		for(int j=i; j>=0; j--) {
			if(mp[s[j]])k+=mp[s[j]];
			else mp[s[j]]='a'+cnt,k+=mp[s[j]],cnt++;
		}
		reverse(k.begin(),k.end());
		v.push_back(k);
	}
	sort(v.begin(),v.end());
	cout<<v.back();
}

J. Luggage Lock

题意:给出一个4位密码锁,每次操作能滑动一个或多个相邻的位置向上或向下移动一格,现在给出多次询问,每次询问给出一个起点和终点,询问起点到终点的最少操作数。

思路: 我们可以先根据起点和终点的位置先得到他们的相对位置,比如起点为“1234”,终点为“2345”,那么他们的相对起点为“0000”,相对终点是“1111”,也就是他们两相减。这样,问题就转化成了起点“0000”到任意终点的最小操作数,这个最小操作数我们可以通过bfs来预处理,每次bfs标记走过的终点,并记录最小步数即可。

代码:

map<string,int>mp;
void bfs() {
	queue<pair<string,int>>q;
	string s="0000";
	q.push({s,0});
	while(!q.empty()) {
		string p=q.front().first;
		int step=q.front().second;
		q.pop();
		for(int i=0; i<4; i++) {
			for(int j=i; j<4; j++) {
				string t=p,tt=p;
				for(int k=i; k<=j; k++) {
					if(t[k]=='9')t[k]='0';
					else t[k]++;
					if(tt[k]=='0')tt[k]='9';
					else tt[k]--;
				}
				if(!mp[t]&&t!="0000")mp[t]=step+1,q.push({t,step+1});
				if(!mp[tt]&&tt!="0000")mp[tt]=step+1,q.push({tt,step+1});
			}
		}
	}
}
void solve() {
	string kk,a,b;
	cin>>a>>b;
	for(int i=0; i<4; i++) kk+=(b[i]-a[i]+10)%10+'0';
    cout<<mp[kk]<<endl;
}

B. Bitwise Exclusive-OR Sequence

题意:给你一个n,表示有n个点,给你m个a,b,w,表示点a的权值和点b的权值异或值为w,求有可能的点权中最小的点权之和。

思路:因为对于二进制来说,每个位数的异或是独立的,是互不影响的,并且若已知一个连通块中某个点权的某个二进制位值,那么其它点权的该二进制位值就都知道了,所以只需枚举各个连通块中随便的一个点权的二进制位即可,并且二进制是0的情况和二进制是1的情况是对称的,取min累加即可,具体实现见代码与注释。

代码:

vector<PII> e[maxn];
bool st[maxn];
int n,m,ans=0,fa[maxn],sum[maxn],res[40],now[maxn];
//sum用来记录连通块大小,res用来记录各个位上的1的个数之和,now来记录当前节点的权值 
int find(int x) {//并查集用来记录每个连通块的大小 
	if(x!=fa[x])return fa[x]=find(fa[x]);
	return x;
}
void dfs(int u) {
	st[u]=true;
	for(auto x:e[u]) {
		int a=x.first,b=x.second;
		if(st[a]) {//如果已经走过了,则看看是否会发生冲突,若会发生冲突则输出-1 
			if((now[a]^now[u])!=b) {
				cout<<-1<<endl;
				exit(0);
			}
		} else {
			now[a]=(now[u]^b);//根据上一个节点的权值得到下一个节点的权值 
			for(int i=0; i<=30; i++)res[i]+=((now[a]>>i)&1);// 将各个位上的1加入总和中 
			dfs(a);
		}
	}
}
void solve() {
	cin>>n>>m;
	for(int i=1; i<=n; i++)fa[i]=i,sum[i]=1;
	for(int i=1; i<=m; i++) {
		int x,y,w;
		cin>>x>>y>>w;
		e[x].push_back({y,w});
		e[y].push_back({x,w});
		int fx=find(x),fy=find(y);
		if(fx!=fy)sum[fx]+=sum[fy],fa[fy]=fx;//计算连通块大小 
	}
	for(int i=1; i<=n; i++) {
		if(find(i)!=i)continue;//一个连通块只跑一次 
		for(int j=0; j<=30; j++)res[j]=0;
		dfs(i);
		for(int j=0; j<=30; j++)ans+=min(res[j],sum[i]-res[j])*(1<<j);//总共有两种情况,它们是互补的,取min值 
	}
	cout<<ans<<endl;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值