Problem B:
套路:暴力确定前两个(或者一个)配对状态 则剩余状态也能确定. 这种类型前期感觉经常出.
Problem C:
题意:一条直线先有n个点 每个点在位置x[i],价值为a[i],初始在s点 最多走K单位距离.n<=1e5,问最多能得到的价钱.
从s起 刚开始向左 或者 向右 然后最多改变一次方向(一直改变方向不是很迷...)
然后枚举刚开拿了左边多少个点,二分最远还能到右边哪一个点.对于初始右边也是如此.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> ii;
const int N=2e5+20,inf=0x3f3f3f3f;
ll n,s,K,pre[N],pos;
struct node{
ll x,w;
}a[N];
bool cmp(node a,node b)
{
return a.x<b.x;
}
ll work(int k,int cur)
{
int l=pos+1,r=n;
ll res=pos;
while(l<=r)
{
int m=l+r>>1;
if(a[m].x-a[cur].x<=k)
res=m,l=m+1;
else
r=m-1;
}
// cout<<cur<<' '<<k<<' '<<res<<' '<<pos<<' ';
return pre[res]-pre[pos];
}
ll Work(int k,int cur)
{
int l=1,r=pos;
ll res=pos;
while(l<=r)
{
int m=l+r>>1;
if(a[cur].x-a[m].x<=k)
res=m,r=m-1;
else
l=m+1;
}
return pre[pos]-pre[res-1];
}
int main()
{
cin>>n>>s>>K;
for(int i=1;i<=n;i++)
scanf("%lld%lld",&a[i].x,&a[i].w);
sort(a+1,a+1+n,cmp);
pos=n;
for(int i=1;i<=n;i++)
if(a[i].x>s)
{
pos=i;
break;
}
for(int i=n;i>=pos;i--)
a[i+1]=a[i];
a[pos].x=s,a[pos].w=0,n++;
for(int i=1;i<=n;i++)
pre[i]=pre[i-1]+a[i].w;
ll ans=0;
for(int i=1;i<=pos;i++)
{
ll ned=abs(a[i].x-a[pos].x),val=0;
ll k=K;
if(k>=ned)
{
k-=ned;
val+=pre[pos]-pre[i-1];
val+=work(k,i);
ans=max(ans,val);
// cout<<ans<<endl;
}
else
break;
}
for(int i=pos;i<=n;i++)
{
ll ned=abs(a[i].x-a[pos].x),val=0;
ll k=K;
if(k>=ned)
{
k-=ned;
val+=pre[i]-pre[pos];
val+=Work(k,i);
ans=max(ans,val);
}
else
break;
}
cout<<ans<<endl;
return 0;
}
Problem D
题意:给出n个数的序列a,可以任意改变序列a元素的位置 要求最终序列相邻元素不能相同
n,a[i]<=1e5,输出满足条件的序列中 字典序最小的哪一个.
n个数的序列相邻要不同 则频率最高为n/2(上取整),否则无解.
构造:加入已经放了前i个数, 第i+1个数应该放哪一个?
若当前频率最高*2 > n-i 则第i+1个数 只能放频率最高的.
否则 第i+1个数没有限制,放当前最小的并且和前面不同即可.然后用set维护一下.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> ii;
const int N=2e5+20,inf=0x3f3f3f3f;
multiset<int> a;
set<ii> s;
int n,x,cnt[N];
int getmx()
{
return s.rbegin()->second;
}
void use(int x)
{
s.erase(ii(cnt[x],x));
--cnt[x];
s.insert(ii(cnt[x],x));
a.erase(a.find(x));
}
int main()
{
int mx=0;
cin>>n;
for(int i=0;i<n;i++)
scanf("%d",&x),cnt[x]++,mx=max(mx,x),a.insert(x);
for(int i=1;i<=mx;i++)
{
if(cnt[i])
s.insert(ii(cnt[i],i));
if(cnt[i]>(n+1)/2)
{
puts("-1");
return 0;
}
}
int pr=-1;
for(int i=0;i<n;i++)
{
if(cnt[getmx()]*2>n-i)
{
int k=getmx();
cout<<k<<' ';
use(k),pr=k;
}
else
{
int k=*a.begin();
if(k==pr)
k=*a.upper_bound(k);
cout<<k<<' ';
use(k),pr=k;
}
}
return 0;
}