Codeforces Round #723 (Div. 2)
A. Mean Inequality
Example
input
3
3
1 2 3 4 5 6
2
123 456 789 10
1
6 9
output
3 1 4 2 5 6
123 10 456 789
9 6
题目大意:
给一个2 n长的元素不重复的数组,任意交换位置,使得任一元素的左右两元素之和不等于本身的两倍,求这个新的数组。
思路:
先从简单的看起,假设a<b<c 或c<b<a, a+c=2 b,那么a,b,c就构成一个等差数列,我们的目的是让它不是等差数列,只要构造成b,a,c 或a,c,b就行了,即 高低高,低高低。
代码:
#include<algorithm>
#include<iostream>
#include<cmath>
#define int long long
using namespace std;
int a[100];
signed main()
{
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
n*=2;
for(int i=0;i<n;++i)
{
cin>>a[i];
}
sort(a,a+n);
for(int i=0;i<n/2;++i)
{
cout<<a[i]<<' ';
cout<<a[n-i-1]<<' ';
}
cout<<endl;
}
return 0;
}
B. I Hate 1111
Example
input
3
33
144
69
output
YES
YES
NO
题目大意:
给你一个数,问你这个数能不能用任意个11,111,1111…相加得来。
思路:
数论,任意互质的正整数a,b,a* n+b* m所表示不出来的最大数是a* b-a-b.
因为11与111互质,所以11* 111-11-111=1099,即只要用这两个数字,就可以表示出>1099的数字,那么1-1099可以直接暴力求出来是否可以用11和111表示.
代码:
#include<algorithm>
#include<iostream>
#include<cmath>
#include<map>
#define int long long
using namespace std;
map<int,bool>ma;
signed main()
{
int t;
for(int i=0;i<=1100;i+=11)
{
for(int j=0;j<=1100;j+=111)
{
if(i+j<=1100)
{
ma[i+j]=1;//求1-1099可以被11和111表示出来的数字
}
}
}
cin>>t;
while(t--)
{
int n;
cin>>n;
if(n>1099||ma[n])cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}
简化版本:
signed main()
{
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
if(n/110>=n%11)cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}
C. Potions
Example
input
6
4 -4 1 -3 1 -3
output
5
题目大意:
给一个数组,初始时你血量为0,元素从左到右,可以选择加上或者不加上,要求每时每刻血量不为负数,求最终最大的元素个数。
思路:
优先队列,从左到右,每个值都先吃进去,同时把负值塞入小顶堆优先队列,如果血量变成负数,就把之前吃进去的最小值吐出来,ans-1,每吃一个就求一次最大长度。
两题都可以这样做…好水啊。而且白书上面有原题…
代码:
#include<algorithm>
#include<iostream>
#include<cmath>
#define int long long
using namespace std;
priority_queue<int,vector<int>,greater<int>>p;
signed main()
{
int n;
cin>>n;
int h=0;
int ans=0;
int temp=0;
for(int i=0;i<n;++i)
{
int a;
cin>>a;
if(a<0)
{
p.push(a);
}
h+=a;
++temp;
if(h<0)
{
--temp;
h-=p.top();
p.pop();
}
ans=max(ans,temp);
}
cout<<ans<<endl;
return 0;
}
D. Kill Anton
Example
input
4
ANTON
NAAN
AAAAAA
OAANTTON
output
NNOTA
AANN
AAAAAA
TNNTAOOA
题目大意:
给一个只有 A N T O 的字符串,可以交换相邻的字符,求最大还原步数的改变后的字符串。
思路:
暴力枚举每个字符串的全排列,记录最大的逆序对数,那个字符串就是花最多步数的答案。
cf大佬的代码:
#include<bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#define int int64_t
typedef tree<pair<int,char>, null_type, less<pair<int,char>>, rb_tree_tag, tree_order_statistics_node_update> ordered_set;
string s;
int check(string s1)
{
ordered_set os;
int ans=0;
deque<int>store[4];
for(int i=0;i<s1.size();i++)
{
os.insert({
i,s1[i]});
if (s1[i]=='A'){
store[0].push_back(i);}
else if (s1[i]=='N'){
store[1].push_back(i);}
else if (s1[i]=='O'){
store[2].push_back(i);}
else{
store[3].push_back(i);}
}
for(int i=0;i<s.size()-1;i++)
{
int x=0;
if(s[i]=='N'){
x=1;}
else if(s[i]=='O'){
x=2;}
else if(s[i]!='A'){
x=3;}
int y=x;
x=store[x].front();
store[y].pop_front();
ans+=os.order_of_key({
x,s[i]});
auto it=os.find({
x,s[i]});
os.erase(it);
}
return ans;
}
signed main()
{
int t;
cin>>t;
while(t--)
{
cin>>s;
string s1,s2,s3,s4;
for(auto it:s)
{
if(it=='A'){
s1+=it;}
else if(it=='N'){
s2+=it;}
else if(it=='O'){
s3+=it;}
else{
s4+=it;}
}
vector<string>z{
s1,s2,s3,s4};
string ans;
int ma=-1;
do
{
string gh;
for(string it:z){
gh+=it;}//以字典序最小的样子开始
int pres=check(gh);
if(pres>ma)
{
ma=pres;
ans=gh;
}
}while(next_permutation(z.begin(),z.end()));
cout<<ans<<endl;
}
return 0;
}