Educational Codeforces Round 161 (Rated for Div. 2) A-F

链接:Dashboard - Educational Codeforces Round 161 (Rated for Div. 2) - Codeforces

A. Tricky Template

题意:给出a,b,c三个字符串,找出一个字符串t使得其与a、b匹配,不与c匹配;匹配的方式有,如果ti是小写字母,那么试图与他匹配的字符串s,si应该等于他;ti是大写字母,si应该不等于他。

思路:如果ai、bi都是相等的,那看c是否是相等,不是可以构造;ai不等于bi,看ci是否与其中一个相等,是可以构造,不是不行。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define endl '\n'
const int N = 1e5 + 10;
//const int mod = 998244353;

void solve()
{
	int n;
	cin>>n;
	string a,b,c;
	cin>>a>>b>>c;
	bool flag=false;
	for(int i=0;i<n;i++){
		if(a[i]==b[i]){
			if(c[i]==a[i]){
				continue;
			}
			else flag=true;
		}
		else if(a[i]!=b[i]){
			if(c[i]==a[i]||c[i]==b[i]){
				continue;
			}
			else flag=true;
		}
	} 
	if(flag) cout<<"YES"<<endl;
	else cout<<"NO"<<endl;
	
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
    int t;
    t=1;
    cin>>t;
    while(t--){
    	solve();
	}
    
    return 0;
}

B. Forming Triangles

题意:有n条棍子,挑出三条组成一个合法的三角形,说明方案数量。

思路:题中说了不同的棍子长度的形式,是2^(ai)次方,说明只能做等边或者等腰,接下来只要统计各类长度有多少根,组合一下就可以。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
//#define endl '\n'
const int N = 1e5 + 10;
//const int mod = 998244353;




void solve()
{
	int n;
	cin>>n;
	map<int,ll> q;
	for(int i=1;i<=n;i++){
		int x;
		cin>>x;
		q[x]++;
	}
	ll ans=0;
	ll res=0;
	for(auto it:q){
		if(it.second>=3){
			ans+=it.second*(it.second-1)*(it.second-2)/6;
		}
		if(it.second>=2){
			ans+=it.second*(it.second-1)/2*res;
		}
		res+=it.second;
	}
	cout<<ans<<endl;
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
    int t;
    t=1;
    cin>>t;
    while(t--){
    	solve();
	}
    
    return 0;
}

C. Closest Cities

题意:n个城市,给出他们在横轴上的坐标,当从一个城市前面离他最近的城市的代价为1,其他情况代价为俩者的距离,给出q个询问,求x和y的最近距离。

思路:从左从右跑俩遍前缀和,利用前缀和统计区间答案。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
//#define endl '\n'
const int N = 1e5 + 10;
//const int mod = 998244353;

bool check(vector<int> &a,int id){
	int disl=(id==0?1e9+7:a[id]-a[id-1]);
	int disr=(id+1==a.size()?1e9+7:a[id+1]-a[id]);
	if(disl>disr){
		return true;
	}
	else return false;
}

void solve()
{
	int n;
	cin>>n;
	vector<int> a(n);
	for(int i=0;i<n;i++){
		cin>>a[i];
	}	
	vector<ll> pre(n),rev(n);
	for(int i=1;i<n;i++){
		pre[i]=pre[i-1]+(check(a,i-1)?1:a[i]-a[i-1]);
	}
	for(int i=n-2;i>=0;i--){
		rev[i]=rev[i+1]+(!check(a,i+1)?1:a[i+1]-a[i]);
	}
	int q;
	cin>>q;
	while(q--){
		int x,y;
		cin>>x>>y;--x;--y;
		if(x>y){
			cout<<rev[y]-rev[x]<<endl;
		}
		else{
			cout<<pre[y]-pre[x]<<endl;
		}
	}
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
    int t;
    t=1;
    cin>>t;
    while(t--){
    	solve();
	}
    
    return 0;
}

D. Berserk Monsters

题意:n只怪兽,各有攻击力和防御力,每轮会攻击彼此左右,当此轮受到的伤害大于防御力,死亡;询问每轮死亡怪物数量。

思路:直接模拟,走一遍计算死亡的,然后死亡的不进到下一个次队列里面,死亡的走一遍,修改死亡的怪物的左边的右边和右边的左边,方便下一次找左右,重复以上。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
//#define endl '\n'
const int N = 1e5 + 10;
//const int mod = 998244353;


void solve()
{
	int n;
	cin>>n;
	vector<int> atk(n+2),def(n+2);
	atk[0]=def[0]=atk[n+1]=def[n+1]=0;
	queue<int> q;
	for(int i=1;i<=n;i++){
		cin>>atk[i];
		q.push(i);
	} 
	for(int i=1;i<=n;i++){
		cin>>def[i];
	}
	vector<int> l(n+2),r(n+2);
	for(int i=1;i<=n;i++){
		l[i]=i-1;
		r[i]=i+1;
	}
	vector<int> ans(n+1);
	vector<int> book(n+1);
	int len=0;
	int cnt=0;
	while(1){
		int cnt=0;
		vector<int> dead;
		while(!q.empty()){
			auto temp=q.front();
			q.pop();
			if(book[temp]>=1){
				continue;
			}
			if(atk[l[temp]]+atk[r[temp]]>def[temp]){
				dead.push_back(temp);
				book[temp]++;
				cnt++;
			}
		}
		if(!cnt){
			break;
		}
		set<int> s;
		for(auto it:dead){
			if(l[it]>=1){
				r[l[it]]=r[it];
				if(book[l[it]]>=1) continue;
				else{
					s.insert(l[it]);
				}
			}
			if(r[it]<=n){
				l[r[it]]=l[it];
				if(book[r[it]]>=1) continue;
				else{
					s.insert(r[it]);
				}
			}
		}
		for(auto it:s){
			q.push(it);
		}
		ans[++len]=cnt;
	}
	for(int i=1;i<=n;i++){
		cout<<ans[i]<<" ";
	}
	cout<<endl;
	
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
    int t;
    t=1;
    cin>>t;
    while(t--){
    	solve();
	}
    
    return 0;
}

E. Increasing Subsequences

题意:给出x,要构造一个长度小于200的序列使得其中的上升子序列数量为x。

思路:当加入一个数小于前面所有数字的时候,序列上升子序列数量s不变;当大于的前面所有数字的时候的时候,s=s*2;由此递归回去算x的序列。详情可以看Educational Codeforces Round 161 Editorial - Codeforces

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
//#define endl '\n'
const int N = 1e5 + 10;
//const int mod = 998244353;
vector<int> f(ll x){
	vector<int> res;
	if(x==2){
		res.push_back(0);
	}
	else if(x&1){
		res=f(x-1);
		res.push_back(*min_element(res.begin(), res.end()) - 1); 
	
	} else {
    res = f(x / 2);
    res.push_back(*max_element(res.begin(), res.end()) + 1);
  }
  return res;
}

void solve()
{
	ll n;
	cin>>n;
	auto ans=f(n);
	cout<<ans.size()<<endl;
	for(auto it:ans){
		cout<<it<<" ";
	}
	cout<<endl;
	
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
    int t;
    t=1;
    cin>>t;
    while(t--){
    	solve();
	}
    
    return 0;
}

F. Replace on Segment

题意:对于一个序列a,序列元素从1到x;有操作取x,y,z,区间[x,y]中数字都不等于z,整个区间数字都变为z,求变为统一数字的最小操作次数。

思路:

ps:看的dalao的DP

dp1 i j k代表区间长度i、从j开始、全部为k的操作次数

dp2 i j k代表区间长度i、从j开始、全部不为k的操作次数

dp1[i][j][k]=min(self,dp1[x][j][k]+dp1[i-x][j+x][k]);dp2同理

dp1[i][j][k]=min(self,dp2[i][j][k]+1);

dp2[i][j][k]=min(self,dp2[i][j][others]);

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
//#define endl '\n'
const int N = 2e5 + 10;
const int mod = 1e9 + 7;
int n,m;

int dp1[105][105][105],dp2[105][105][105];//长度为i的区间在j位置开始,全(不)为k的最小修改次数 
void solve()
{
	cin>>n>>m;
	memset(dp1,0,sizeof(dp1));
	memset(dp2,0,sizeof(dp2));
	vector<int> a(n+1);
	for(int i=0;i<n;i++) cin>>a[i];
	for(int i=0;i<=n;i++){
		for(int j=0;j<n;j++){
			for(int k=0;k<=m;k++){
				dp1[i][j][k]=dp2[i][j][k]=1e9;
			}
		}
	} 
	for(int i=0;i<n;i++){
		for(int j=0;j<=m;j++){
			dp1[1][i][j]=(a[i]==j?0:1);
			dp2[1][i][j]=(a[i]==j?1:0);
			//cout<<dp1[1][i][j]<<" "<<dp2[1][i][j]<<endl;
		}
	}
	for(int i=2;i<=n;i++){
		for(int x=0;x+i-1<n;x++){
			for(int y=1;y<=m;y++){
				for(int j=1;j<i;j++){
					dp1[i][x][y]=min(dp1[i][x][y],dp1[j][x][y]+dp1[i-j][x+j][y]);
					dp2[i][x][y]=min(dp2[i][x][y],dp2[j][x][y]+dp2[i-j][x+j][y]);
					dp1[i][x][y]=min(dp1[i][x][y],dp2[i][x][y]+1); 
				}
			}
			for(int y=1;y<=m;y++){
				for(int j=1;j<=m;j++){
					if(j==y){
						continue;
					}
					dp2[i][x][y]=min(dp2[i][x][y],dp1[i][x][j]);
				}
			} 
		}
	}
	//cout<<dp1[3][0][3]<<endl;
	int mx=0x3f3f3f3f;
	for(int i=1;i<=m;i++){
		mx=min(mx,dp1[n][0][i]);
	}
	cout<<mx<<endl;
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
    int t;
    t=1;
    cin>>t;
    while(t--){
    	solve();
	}
    
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱吃芒果的蘑菇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值