开篇碎碎念
其实应该是总结才对,小号打的,赛时ABC三题,rank 3k+,rating change回滚了。
赛后补了下DE
A.Tricky Template
题意:
判断是否能构造出模板链使AB链匹配而C链不匹配,匹配规则:当模板为小写的时候,匹配链对应位置必须相同,当模板为大写时,匹配链必须不同,
解题思路:
因为是和C链不匹配所以特殊关注C链的匹配性,而且只要有一位无法和C链匹配上那么就和C链不匹配。所以容易判断出YES的情况。
当C链和AB链该位置不同时就可以选择模板链小写构造出符合要求的模板
code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl "\n"
const int MAXN=1e5+10;
void sol(){
int n;
cin>>n;
string a,b,c;
cin>>a>>b>>c;
int f=0;
for(int i=0;i<n;i++){
if(a[i]!=c[i] && b[i]!=c[i]){
f=1;
break;
}
}
if(f==1)cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
signed main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int t;
cin>>t;
while(t--){
sol();
}
return 0;
}
B. Forming Triangles
题意:
有 n 根木棒,编号从 1 到 n 。第 i 根木棒的长度是 2^ai 。从给出的n个木棒中选择三根构成一个非退化三角形(面积绝对大于零)的数目。
解题思路
观察长度发现都是二的次幂,两个二的较低次幂的木棍的和是不大于任何一个较高次幂的。所以只可能构成等边或者两腰较长的等腰三角形。
所以存储每个长度的个数,然后进行选择。
code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl "\n"
const int MAXN=3e5+10;
int a[MAXN];
int C3(int x){
return x*(x-1)/2*(x-2)/3;
}
int C2(int x){
return x*(x-1)/2;
}
void sol(){
int n,k,ans=0,tot=0;
cin>>n;
for(int i=1;i<=n;i++){
cin>>k;
a[k]++;
}
for(int i=0;i<=n;i++){
if(a[i]>=3){
ans+=C3(a[i]);
ans+=C2(a[i])*tot;
}
else if(a[i]==2){
ans+=C2(a[i])*tot;
}
tot+=a[i];
a[i]=0;
}
cout<<ans<<endl;
}
signed main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int t;
cin>>t;
while(t--){
sol();
}
return 0;
}
C. Closest Cities
题意:
数轴上有n个城市,分别位于ai(ai升序排列),两个城市的距离为abs(ai-aj)。每个城市到达其最近城市的代价为1,其余城市为距离。
q次询问,分别给出两个城市u.v,问从u到v的最小花费
解题思路
前缀和分别计算从小到大城市的花费和从大到小,两个前缀和数组。
对于前缀和的证明:由于每两个城市之间都是采用的最优策略,所以从a到b就是从1到b的代价减去1到(a-1)的代价
贪心对于每个城市来说他的最近城市一定是和他相邻的城市之一。能使用相邻城市的快速穿梭就使用快速穿梭。
code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl "\n"
const int MAXN=1e5+10;
int a[MAXN],b[MAXN],c[MAXN];
void sol(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
a[0]=-1e16,a[n+1]=1e16;
int ans=0;
for(int i=1;i<n;i++){
if(a[i+1]-a[i]>a[i]-a[i-1]){
ans+=a[i+1]-a[i];
}
else ans+=1;
b[i+1]=ans;
}
b[1]=0;
ans=0;
for(int i=n;i>1;i--){
if(a[i]-a[i-1]>a[i+1]-a[i]){
ans+=a[i]-a[i-1];
}
else ans+=1;
c[i-1]=ans;
}
c[n]=0;
int q,u,v;
cin>>q;
for(int i=1;i<=q;i++){
cin>>u>>v;
if(u>v){
cout<<c[v]-c[u]<<endl;
}
else cout<<b[v]-b[u]<<endl;
}
}
signed main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int t;
cin>>t;
while(t--){
sol();
}
return 0;
}
D. Berserk Monsters
题目意思
有n个怪物,每个怪物的攻击力为ai,防御力是di,每轮每个怪物分别攻击一次它左边的怪兽和一次右边的怪兽(如果存在的话),只有受到的攻击总和大于其防御力的时候会死,输出每一轮死亡的怪兽数目
解题思路
说实话我是为了这个题而记录的整场比赛。首先是一个链表的操作,方便删除死亡的怪兽进行新一轮的计算。但是每个死亡的怪兽不是一旦判定死亡就要更新左右关系,不然可能会存在本该死亡的怪兽,因为它旁边的怪兽也死了,计算的时候就没算到它旁边的怪兽对它的攻击,从而没有死亡。(好叭我是赛后查看数据的时候发现的这个问腿)
于是我增加了一个vector记录每一轮的死亡的怪兽分别是几号,在轮次结束的时候再进行死亡的更新操作。
然后TLE...
观察样例,有些怪兽至始至终都不会死,所以如果判断了多次那么肯定是浪费时间,只有有怪兽死亡才会有新的左右关系变化,所以新建一个vector存一下每次死亡的怪兽的相邻的怪兽
注意特判,在第一次前虽然没有怪兽死亡,但是每个怪兽都有可能死亡,所以都应该加入待判列表
code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl "\n"
const int MAXN=3e5+10;
struct monster{
int a;
int d;
int l;
int r;
}m[MAXN];
int n;
int vis[MAXN],dele[MAXN];
vector<int>del;
vector<int>qdel;
void add(int i){
if(i<1 || i>n)return;
if(!vis[i] && !dele[i]){
vis[i]=1;
qdel.push_back(i);
}
}
void de(int i){
m[m[i].l].r=m[i].r;
m[m[i].r].l=m[i].l;
add(m[i].l);
add(m[i].r);
}
void sol(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>m[i].a;
dele[i]=0;
}
for(int i=1;i<=n;i++){
cin>>m[i].d;
}
m[n+1].a=0,m[0].a=0;
for(int i=1;i<=n+1;i++){
m[i].l=i-1;
m[i-1].r=i;
}
for(int i=1;i<=n;i++){
add(i);
}
for(int i=1;i<=n;i++){
int tot=0;
for(int j=0;j<qdel.size();j++){
int k=qdel[j],ta;
vis[k]=0;
ta=m[m[k].l].a+m[m[k].r].a;
if(ta>m[k].d){
del.push_back(k);
tot++;
}
}
qdel.clear();
for(int j=0;j<del.size();j++){
dele[del[j]]=1;
}
for(int j=0;j<del.size();j++){
de(del[j]);
}
del.clear();
cout<<tot<<' ';
}
cout<<endl;
}
signed main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int t;
cin>>t;
while(t--){
sol();
}
return 0;
}
E. Increasing Subsequences
题意:
给出n,求出一个长度在200以内的,含有严格单调递增子序列个数为n的数列
解题思路:
因为一个数的和空串都算严格单调递增子序列。所以发现长度为k的严格单调数列含有的严格单调递增子序列个数为2^k,进而考虑到n的二进制表达
code
#include<bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;
const int MAXN=3e5+10;
int a[MAXN];
void sol(){
int n,x;
cin>>n;
x=n;
int cnt=0;
vector<int>ans;
while(n){
if(n&1){
a[cnt++]=1;
}
else a[cnt++]=0;
n>>=1;
}
cnt--;
for(int i=0;i<cnt;i++){
ans.push_back(i);
}
for(int i=cnt-1;i>=0;i--){
if((x>>i)&1)ans.push_back(i);
}
cout<<ans.size()<<endl;
for(auto i:ans)cout<<i<<' ';
cout<<endl;
}
signed main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int t;
cin>>t;
while(t--){
sol();
}
}