Codeforces Round #744
A Casimir’s String Solitaire
题意
有个只有A,B,C的字符串 每次删去一个A和B 或者 删去一个B和C 问能否删除完
思路
计算A+C==B 能相等就说明能删除完
代码
#include<cstring>//memset
#include<iostream>//c++
#include<algorithm>//stl
#include<string>
#include<set>
#include<queue>
#include<vector>
#include<cmath>
#include <sstream>
#define N 1005
#define mod 998244353
using namespace std;
typedef long long ll;
int t,n,a,b,c;
string s;
int main()
{
cin>>t;
while(t--)
{
a=b=c=0;
cin>>s;
for(int i=0;i<s.size();i++)
{
if(s[i]=='A')
a++;
else if(s[i]=='B')
b++;
else
c++;
}
if(a+c==b)
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
return 0;
}
B Shifting Sort
题意
给一个数组a 你可以指定l,r(1<=l<r<=n)向左循环移位d
如 123 左循环移动2位 变成 312
问用不超过n次循环移位给数组a进行排序
思路
不超过n次 很容易想到基础排序 每次排序给一位数找到合适的位置 所以我们每次找到剩下没排序中最小的数的位置cnt 和它对应位置i记录下来 差值就是向左循环偏移量 整个偏移的数组(i到cnt)其实就是向右循环偏移1位 利用前面一位覆盖后面一位 从后往前覆盖 实现数组偏移操作
代码
#include<cstring>//memset
#include<iostream>//c++
#include<algorithm>//stl
#include<string>
#include<set>
#include<queue>
#include<vector>
#include<cmath>
#include <sstream>
#define N 1005
#define mod 998244353
using namespace std;
typedef long long ll;
int t,n,a[60],l[60],r[60],cnt;
string s;
int main()
{
ios::sync_with_stdio(false);
cin>>t;
while(t--)
{
cin>>n;
for(int i=1; i<=n; i++)
{
cin>>a[i];
}
int num=1;
cnt=1;
while(cnt<n)
{
int mmin=a[cnt];
for(int i=cnt+1; i<=n; i++)
{
if(a[i]<mmin)
{
mmin=a[i];
r[num]=i;
}
}
if(a[cnt]!=mmin)
{
l[num]=cnt;
for(int i=r[num]; i>cnt; i--)
{
a[i]=a[i-1];
}
num++;
}
a[cnt]=mmin;
cnt++;
}
num--;
cout<<num<<endl;
for(int i=1; i<=num; i++)
{
cout<<l[i]<<" "<<r[i]<<" "<<r[i]-l[i]<<endl;
}
}
return 0;
}
C Ticks
题意
在nxm方格上有一些标记点 问这些标记点是否都能组成左边和右边都至少为k长度(不包括最下面的顶点)的v字型
思路
暴力每一个标记点 把它当作v最下面的顶点向两端延申并记录两端的长度cnt1,cnt2 如果两端的长度最小的都不少于k 则用vis数组把这个v的点标记下来 最后如果方格里面标记的点在vis中未标记 说明这个点无法构成符合条件的v
代码
#include<cstring>//memset
#include<iostream>//c++
#include<algorithm>//stl
#include<string>
#include<set>
#include<queue>
#include<vector>
#include<cmath>
#include <sstream>
#define N 1005
#define mod 998244353
using namespace std;
typedef long long ll;
int t,n,te,tt,num,m,k;
char a[25][25];
int vis[25][25];
int main()
{
ios::sync_with_stdio(false);
cin>>t;
while(t--)
{
memset(vis,0,sizeof(vis));
cin>>n>>m>>k;;
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++)
{
cin>>a[i][j];
}
}
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++)
{
if(a[i][j]=='*')
{
int x1=i-1,y1=j-1,cnt1=0;
while((x1>0)&&(y1>0)&&a[x1][y1]=='*')
{
cnt1++;
x1-=1;
y1-=1;
}
int x2=i-1,y2=j+1,cnt2=0;
while((x2>0)&&(y2<=m)&&a[x2][y2]=='*')
{
cnt2++;
x2-=1;
y2+=1;
}
int te=min(cnt1,cnt2);
if(te>=k)
{
int t1=i,t2=j;
while(t1>=i-te&&t2>=j-te)
{
vis[t1][t2]=1;
t1--;
t2--;
}
t1=i;t2=j;
while(t1>=i-te&&t2<=j+te)
{
vis[t1][t2]=1;
t1--;
t2++;
}
}
}
}
}
int flag=1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(a[i][j]=='*'&&vis[i][j]==0)
{
flag=0;
break;
}
}
if(!flag)
break;
}
if(flag)
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
return 0;
}
D Productive Meeting
题意
有n个人 每个人都有自己的谈话次数 两个人谈话一次双方都会消耗一次次数
问最多能谈话多少次
思路
贪心 用优先队列每次找的两个剩余谈话次数最多的两个人谈话 不为零的再扔进优先队列里面
代码
#include<bits/stdc++.h>
#define N 200005
#define mod 998244353
using namespace std;
typedef long long ll;
int t,n,te,a[N],b[N];
struct node
{
int cnt,num;
node(){};
node(int cc,int nn)
{
cnt=cc;
num=nn;
}
bool operator < (const node &a)const
{
return a.num>num;
}
};
priority_queue<node> qu;
int main()
{
ios::sync_with_stdio(false);
cin>>t;
while(t--)
{
while(!qu.empty())
{
qu.pop();
}
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>te;
if(te<=0)
continue;
qu.push(node(i,te));
}
node t1,t2;
int cnnt=1;
while(qu.size()>1)
{
t1=qu.top();
qu.pop();
t2=qu.top();
qu.pop();
a[cnnt]=t1.cnt;
b[cnnt]=t2.cnt;
cnnt++;
t1.num--;
t2.num--;
if(t1.num>0)
{
qu.push(t1);
}
if(t2.num>0)
{
qu.push(t2);
}
}
cout<<--cnnt<<endl;
for(int i=1;i<=cnnt;i++)
{
cout<<a[i]<<" "<<b[i]<<endl;
}
}
return 0;
}
E1 Permutation Minimization by Deque
题意
给一个n个数的数组 1到n每个数字只出现一次 将这些数字按照数组的顺序 自由选择加到双端队列前面或者后面
寻找 字典序最小的双端队列序列
思路
贪心 如果当前数小于队列最前面的数 就加入队列前 否则加入队列后面
代码
#include<cstring>//memset
#include<iostream>//c++
#include<algorithm>//stl
#include<string>
#include<set>
#include<queue>
#include<vector>
#include<cmath>
#include <sstream>
#define N 1005
#define mod 998244353
using namespace std;
typedef long long ll;
int t,n,te,tt;
string s;
deque<int> qu;
int main()
{
ios::sync_with_stdio(false);
cin>>t;
while(t--)
{
while(!qu.empty())
qu.pop_back();
cin>>n;
cin>>te;
qu.push_back(te);
for(int i=1;i<n;i++)
{
cin>>tt;
if(tt<te)
{
qu.push_front(tt);
te=tt;
}
else
{
qu.push_back(tt);
}
}
while(!qu.empty())
{
cout<<qu.front()<<" ";
qu.pop_front();
}
cout<<endl;
}
return 0;
}
E2 Array Optimization by Deque
题意
给定一个数组 按照数组顺序自由选择加入双端队列d前面或者后面 问队列中最小反转次数是多少(当i小于j di大于dj 是为一个反转)
思路
每一步插在前面或者后面 对后续操作贡献的答案是没有影响的(可贪)
找到队列中比当前数字大的数量,队列中比当前数字小的数量,取一个最小值(比它大的数多 放前面 小的数多 放后面)
每增加一个数 都要去寻找当前比它小的数量和当前比它大的数量 单纯不断排序+2分并不能满足时间 特别是当只有一个重复数时 二分时间复杂度趋近o(n)
- 优化一 去重复(离散化)
一旦去重复再计算比它小的数量就会转变成 区间快速求和 这时 我们就需要线段树或者树状数组来快速求区间和
(借彬宝的线段树模板@彬宝)
代码
#include<cstring>//memset
#include<iostream>//c++
#include<algorithm>//stl
#include<string>
#include<set>
#include<queue>
#include<vector>
#include<cmath>
#include<map>
#include <sstream>
#define N 200005
#define mod 1000000007
using namespace std;
typedef long long ll;
struct node
{
int l,r;
ll num;
}tree[4*N];
ll a[N];
//建树 O(logn)
inline void build(int l,int r,int i)
{
tree[i].l=l;
tree[i].r=r;
tree[i].num=0;
if(l==r)
return ;
int mid=(l+r)>>1;
build(l,mid,i*2);
build(mid+1,r,i*2+1);
}
//单点更新O(logn) 区间更新O(nlogn)
inline void update(int x,int l,int r,int i)
{
if(tree[i].l==tree[i].r)
{
tree[i].num++;
return ;
}
int mid=(l+r)>>1;
if(x<=mid)
update(x,l,mid,i*2);
if(x>mid)
update(x,mid+1,r,i*2+1);
tree[i].num=tree[i*2].num+tree[i*2+1].num;
}
//查询 O(logn)
inline ll query(int l,int r,int i)
{
if(tree[i].l>=l&&tree[i].r<=r)
{
return tree[i].num;
}
if(tree[i].l>r||tree[i].r<l)
return 0;
ll s=0;
int mid=(tree[i].l+tree[i].r)>>1;
if(mid>=l)
s+=query(l,r,i*2);
if(mid<=r)
s+=query(l,r,i*2+1);
return s;
}
map<ll,ll> mp;
map<ll,ll>::iterator it;
ll tt,n,te;
int main()
{
ios::sync_with_stdio(false);
cin>>tt;
while(tt--)
{
mp.clear();
cin>>n;
ll ans=0,cnt=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
mp[a[i]]=1;
}
for(it=mp.begin();it!=mp.end();it++)
{
it->second=++cnt;
}
for(int i=1;i<=n;i++)
{
a[i]=mp[a[i]];
}
build(1,mp.size(),1);
for(int i=1;i<=n;i++)
{
update(a[i],1,mp.size(),1);
ll mmin=query(1,a[i]-1,1);
ll mmax=i-query(1,a[i],1);
ans+=min(mmin,mmax);
}
cout<<ans<<endl;
}
return 0;
}