链接: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;
}