文章目录
A.Polycarp and Sums of Subsequences
最大值一定是三个数的和,次大值一定是最大的两个数的和,次次大值一定是最大值和次大值的和。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
int t;
cin>>t;
while(t--){
vector<int>v;
for( int i=0;i<7;i++){
int x;
cin>>x;
v.push_back(x);
}
sort(v.begin(),v.end());
int x=v.size()-1;
cout<<v[x]-v[x-1]<<" "<<v[x]-v[x-2]<<" "<<v[x-2]+v[x-1]-v[x]<<endl;
}
}
B.Missing Bigram
直接构造字符串即可
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
int t;
cin>>t;
while(t--){
int n;
cin>>n;
string ans;
cin>>ans;
for( int i=1;i<n-2;i++){
string s;
cin>>s;
if(s[0]==ans[ans.size()-1]){
ans+=s[1];
}
else {
ans+=s;
}
}
for( int i=ans.size();i<n;i++){
ans+='b';
}
cout<<ans<<endl;
}
}
C. Paint the Array
找最大公因数,如果存在答案,那么答案一定是奇数列或偶数列的最大公因数,反之不存在答案。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=110;
ll w[N];
int main(){
int t;
cin>>t;
while(t--){
int n;
cin>>n;
for( int i=0;i<n;i++){
cin>>w[i];
}
ll gcd_even=w[0],gcd_odd=w[1];
for( int i=0;i<n;i++){
if(i%2==0){
gcd_even=__gcd(gcd_even,w[i]);
}
else {
gcd_odd=__gcd(gcd_odd,w[i]);
}
}
int flag=1;
for( int i=0;i<n;i+=2){
if(w[i]%gcd_odd==0){
flag=0;
}
}
if(flag==1){
cout<<gcd_odd<<endl;
continue;
}
flag=1;
for( int i=1;i<n;i+=2){
if(w[i]%gcd_even==0){
flag=0;
}
}
if(flag==1){
cout<<gcd_even<<endl;
}
else cout<<0<<endl;
}
return 0;
}
D. Array and Operations
贪心算法,每次找两个相隔k的数相除。(不能找相邻的数相除,因为两个数相等的话不是最优解)
#include<bits/stdc++.h>
using namespace std;
const int N=100100;
typedef long long ll;
int w[N];
int cmp( int a,int b){
return a>b;
}
int main(){
int t;
cin>>t;
while(t--){
int n,k;
cin>>n>>k;
for( int i=1;i<=n;i++){
scanf("%d",&w[i]);
}
sort(w+1,w+1+n,cmp);
k=min(k,n/2);
ll ans=0;
for( int i=1;i<=k;i++){
ans+=w[i+k]/w[i];
}
for( int i=k*2+1;i<=n;i++){
ans+=w[i];
}
cout<<ans<<endl;
}
return 0;
}
E. Singers’ Tour
公式推导。
#include<bits/stdc++.h>
using namespace std;
const int N=200100;
typedef long long ll;
ll w[N];
ll ww[N];
int main(){
int t,n;
cin>>t;
while(t--){
cin>>n;
ll sum=0;
ll cnt=(1+n)*n/2;
for( int i=0;i<n;i++){
cin>>w[i];
sum+=w[i];
}
if(sum%cnt!=0){
cout<<"NO"<<endl;
continue;
}
else sum/=cnt;
// cout<<sum<<endl;
for( int i=0;i<n;i++){
ww[i]=w[i]-w[(i-1+n)%n];
ww[i]=ww[i]-sum;
if(ww[i]%n!=0){
cout<<"NO";
goto endd;
}
ww[i]=-ww[i]/n;
if(ww[i]<=0){
cout<<"NO";
goto endd;
}
}
cout<<"YES"<<endl;
for( int i=0;i<n;i++){
printf("%lld ",ww[i] );
}
endd:
cout<<endl;
}
return 0;
}
F. Reverse
bfs搜索,注意要去掉字符串的前缀0,这里直接转为int去0
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
string sa,sb;
ll a,b;
string int_to_string( ll x){
string res;
while(x){
res+=x%2+'0';
x/=2;
}
reverse(res.begin(),res.end());
return res;
}
ll string_to_int(string s){
ll res=0;
for( int i=0;i<s.size();i++){
res=res*2+s[i]-'0';
}
return res;
}
int bfs( ){
set<ll>se;
queue<ll>q;
se.insert(a);
q.push(a);
while(!q.empty()){
ll now=q.front();
q.pop();
if(now==b) return 1;
string s=int_to_string(now)+"0";
// cout<<string_to_int(s)<<endl;
reverse(s.begin(),s.end());
ll temp=string_to_int(s);
if(temp>0&&se.find(temp)==se.end()){
se.insert(temp);
q.push(temp);
}
s=int_to_string(now)+"1";
reverse(s.begin(),s.end());
temp=string_to_int(s);
if(temp>0&&se.find(temp)==se.end()){
se.insert(temp);
q.push(temp);
}
}
return 0;
}
int main(){
cin>>a>>b;
sa=int_to_string(a);
sb=int_to_string(b);
if(bfs()==1) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
return 0;
}
G. Trader Problem
并查集。
首先将数列a和b放在一起排序,注意要标记元素属于a还是属于b,然后差分,将差和q放在一起排序。
从小到大遍历差分数组,如果元素属于查询,那么存储答案,如果元素不属于查询,那么将两端序列合并。
合并的方法是启发式合并set,将小的set插入到大的set中,并用并查集维护。
这里有两个set数组,其中aset表示已经选择的元素集合,bset表示没有选择的元素的集合,sum表示所有aset中的元素的和。
合并时,先将aset插入aset,bset插入bset,然后比较aset的最小值和bset的最大值,并且更新sum
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=400100;
int a[N],b[N],q[N];
int fa[N];
ll ans[N],sum;
multiset<int>aset[N],bset[N];
struct event{
int div,type,pos;
//div表示两个数的差值,type表示数据类型,pos表示原数的位置
};
int find(int x){
if(fa[x]!=x) fa[x]=find(fa[x]);
return fa[x];
}
void merge(int a,int b){
a=find(a),b=find(b);
if(aset[a].size()+bset[a].size()<aset[b].size()+bset[b].size())
swap(a,b);
for( auto it: aset[b])
aset[a].insert(it);
for( auto it: bset[b])
bset[a].insert(it);
aset[b].clear();
bset[b].clear();
while(!bset[a].empty()&&!aset[a].empty()&&*aset[a].begin()<*bset[a].rbegin()){
sum-=*aset[a].begin();
sum+=*bset[a].rbegin();
aset[a].insert(*bset[a].rbegin());
bset[a].insert(*aset[a].begin());
aset[a].erase(aset[a].begin());
bset[a].erase(--bset[a].end());
}
fa[b]=a;
}
int cmp(event a,event b){
if(a.div!=b.div)
return a.div<b.div;
else return a.type<b.type;
}
int main(){
int n,m,qq;
cin>>n>>m>>qq;
for( int i=0;i<n;i++){
scanf("%d",&a[i]);
}
for( int i=0;i<m;i++){
scanf("%d",&b[i]);
}
for( int i=0;i<qq;i++){
scanf("%d",&q[i]);
}
vector<pair<int,int> >v;
//1表示已经拿到的,0表示未拿到的
for( int i=0;i<n;i++) v.push_back(make_pair(a[i],1));
for( int i=0;i<m;i++) v.push_back(make_pair(b[i],0));
sort(v.begin(),v.end());
sum=accumulate(a,a+n,0ll);
for(int i=0;i<v.size();i++){
fa[i]=i;
if(v[i].second) aset[i].insert(v[i].first);
else bset[i].insert(v[i].first);
}
vector<event>ev;
for( int i=0;i<n+m-1;i++){
ev.push_back((event){v[i+1].first-v[i].first,0,i});
}
for( int i=0;i<qq;i++) ev.push_back((event){q[i],1,i});
sort(ev.begin(),ev.end(),cmp);
for( int i=0;i<ev.size();i++){
if(ev[i].type==0)
merge(ev[i].pos,ev[i].pos+1);
else
ans[ev[i].pos]=sum;
}
for( int i=0;i<qq;i++){
printf("%lld\n",ans[i]);
}
}