首先,庆祝自己上了绿名
A. Casimir’s String Solitaire
题目描述:
一个字符串包括A,B,C三种字符,有俩种操作可以选择
1.删除一个A和一个B
2.删除一个B和一个C
问最后能不能将这个字符串清空
思路:
统计A,B,C的数量为a,b,c,b=a+c则YES,否则NO
#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main(){
int t;
cin>>t;
while(t--){
int a=0,b=0,c=0;
string s;
cin>>s;
for(int i=0;i<s.length();i++){
if(s[i]=='A')a++;
if(s[i]=='B')b++;
if(s[i]=='C')c++;
}
if(b==a+c)cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}
B. Shifting Sort
题目描述:
对于给定的序列,[l,r]代表选择的区间,d代表前d位不动,区间后几位移动到最前面去,
例如[2,3,4,5,6,7]选择区间[1,5],d为2则->[4,5,6,2,3,6,7]
问给定的序列,使用不多于n次这样的操作使得整个序列不降序排列
思路:
从下标2开始,找到第一个大于它的数(因为n比较小,可以之间暴力遍历),将它插进去(需要调整整个区间),通过开三个数组l,r.d记录每次操作的l,r,d.l[k]为第一个大于它的数,r[k]为它前面的第一个数,d[k]为这段的长度.
#include<bits/stdc++.h>
using namespace std;
#define int long long
int a[100];
int l[100],r[100],d[100];
signed main(){
int t;
cin>>t;
while(t--){
int n;
cin>>n;
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
int k=0;
for(int i=2;i<=n;i++){
int flag=i;
for(int j=1;j<i;j++){
if(a[j]>a[i]){
int temp=a[i];
for(int p=i;p>j;p--){
a[p]=a[p-1];
}
a[j]=temp;
flag=j;
break;
}
}
if(flag!=i){
l[k]=flag;
r[k]=i;
d[k++]=i-flag;
}
}
cout<<k<<endl;
for(int i=0;i<k;i++){
cout<<l[i]<<" "<<r[i]<<" "<<d[i]<<endl;
}
}
return 0;
}
C. Ticks
题目描述:
对于n*m的方格,里面有一些⭐的点,对于给定的k,能不能画长度大于k的v图案使得所有的⭐都被覆盖过
思路:
n不大,直接暴力模拟
#include<bits/stdc++.h>
using namespace std;
#define int long long
//char c[20][25];
int flag[20][25];
string c[20];
signed main(){
int t,l;
cin>>t;
while(t--){
int n,m,k,left,right,up,o=1;
cin>>n>>m>>k;
for(int i=1;i<=n;i++){
cin>>c[i];
c[i]=" "+c[i];
for(int j=1;j<=m;j++){
l=0;
flag[i][j]=0;
if(c[i][j]=='*'){
flag[i][j]=1;
left=j,right=j,up=i;
while(up>=2&&left>=2&&right<=m-1&&c[up-1][left-1]=='*'&&c[up-1][right+1]=='*'){
l++;
left--;
right++;
up--;
}
if(l>=k){
left=j,right=j,up=i;
flag[i][j]=0;
while(up>=2&&left>=2&&right<=m-1&&c[up-1][left-1]=='*'&&c[up-1][right+1]=='*'){
flag[up-1][left-1]=0;
flag[up-1][right+1]=0;
left--;
right++;
up--;
}
}
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(flag[i][j]==1){
cout<<i<<" "<<j<<endl;
o=0;
break;
}
}
}
if(o)cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}
D. Productive Meeting
题目描述:
给定一个序列的人,每个人都有一些谈话次数,问这个序列最多能进行谈话多少次
思路:
每次找到拥有谈话次数最多的人,让他与谈话次数最少的人进行一次谈话,不断模拟这个过程,可以用set完成这种操作
#include<bits/stdc++.h>
using namespace std;
#define int long long
set<pair<int,int> > st;
int l[200005],r[200005];
signed main(){
int t;
scanf("%lld",&t);
while(t--){
int n;
scanf("%lld",&n);
int a;
for(int i=1;i<=n;i++){
scanf("%lld",&a);
if(a!=0)st.insert(pair<int,int>(a,i));
}
int k=0;
while(st.size()>1){
auto q=*st.begin();
auto p=*st.rbegin();
q.first--;
p.first--;
if(p.second>q.second){
l[k]=q.second;
r[k]=p.second;
}
else{
l[k]=p.second;
r[k]=q.second;
}
k++;
st.erase(st.begin());
if(p.first>0){
st.insert(pair<int,int> (p.first,p.second));
}
auto it=st.end();
it--;
st.erase(it);
if(q.first>0){
st.insert(pair<int,int> (q.first,q.second));
}
}
printf("%lld\n",k);
for(int i=0;i<k;i++){
printf("%lld %lld\n",l[i],r[i]);
}
st.clear();
}
return 0;
}
E1. Permutation Minimization by Deque
题目描述:
对于给定的序列,你可以按照从左到右的顺序将每个点选择添加到队列的头或者尾部,问这样操作下来能得到字典序最小的序列是怎样的
思路:
贪心的想法,拿21312来讲,先将2放进去,对于1来讲,2>1,1放在前面就可以降低字典序,所以1放前面,然后对于3来讲,队列头为1,3放前面则会提高字典序,3放后面,然后对于1来讲,队列头为1,将1放在前面显然比1放在后面的字典序小,
所以得出一个结论,对于当前的点来说,比队列头小或者等于则放在前面,或者放在后面,具体的实现可以用双端队列来完成.
#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main(){
int t;
scanf("%lld",&t);
while(t--){
int n;
scanf("%lld",&n);
deque<int> q;
int a;
scanf("%lld",&a);
q.push_back(a);
for(int i=2;i<=n;i++){
scanf("%lld",&a);
if(a>q.front())q.push_back(a);
else q.push_front(a);
}
while(!q.empty()){
printf("%lld ",q.front());
q.pop_front();
}
printf("\n");
}
return 0;
}
E2. Array Optimization by Deque
题目描述:
与E1题描述差不多,但是所求完全不一样,这题通过选择放前面或者放后面的操作最终达到逆序对最小的序列
思路:
思路很简单,对于当前要放进去的点,考虑它与之前的点逆序的情况,也就是这个点当前贡献的逆序对,当之前的点比它小的数比它大的数多,则放前面会形成更少的逆序对,反之,放后面会形成更少的逆序对,一开始我选择通过set容器维护这个操作,set容器是有序的,通过二分查找就能判断当前点对应之前点的位置,不过,这个只能返回一个迭代器,而得不到下标,想法破灭(查了很多资料也没有得到set下标的方法,有会的大佬可以教一下),然后看别人题解是用树状数组求逆序对的方法,因为ai的范围为[-1e9,1e9],所以这个不能用值作为下标,可以将整个数组排序,然后去重,找到该值对应的序号作为下标.接下来就是树状数组求逆序对的板子了
#include<bits/stdc++.h>
using namespace std;
#define int long long
int cnt,n;
int c[100005];
int a[100005];
vector<int> all;
int lowbit(int x){
return x&(-x);
}
void updata(int i,int v){
while(i<=n){
c[i]+=v;
i+=lowbit(i);
}
}
int getsum(int i){
int res=0;
while(i){
res+=c[i];
i-=lowbit(i);
}
return res;
}
//deque<int> q;
signed main(){
int t;
scanf("%lld",&t);
while(t--){
cnt=0;
scanf("%lld",&n);
for(int i=1;i<=n;i++){
c[i]=0;
scanf("%lld",&a[i]);
all.push_back(a[i]);
}
sort(all.begin(),all.end());
all.erase(unique(all.begin(),all.end()),all.end());
for(int i=1;i<=n;i++){
a[i]=lower_bound(all.begin(),all.end(),a[i])-all.begin()+1;
int l=getsum(a[i]-1);
int t=getsum(a[i])-getsum(a[i]-1);
if(l<=(i-l-1-t))cnt+=l;
else cnt+=(i-l-1-t);
cout<<cnt<<endl;
updata(a[i],1);
}
printf("%lld\n",cnt);
all.clear();
}
return 0;
}