东营市东营网站设计地推拉新接单网
打的依托,A一直错,B写的好像麻烦了
A略
B
最简单的想法是:保证最后一步操作时所有数非0,我们可以将序列化为左右两部分,哪一部分有0则这一部分进行一次操作,最后这两部分进行一次操作
C
首先,x和y相等直接不可能。观察式子发现如果(x+k)xor(y+k)中的xor发挥的作用和+一样,那么左右两边相等,即x+k和y+k的二进制下的1不出现在同一位上。我们让x和y较大的那个加一个数能够最高位进一位,其他位为0,那么那个小的数即使加上最高位也不到大数加后最高位,此时同一位最多出现一个1
D
首先贪心分析会吃掉n/(k+1)盘寿司,倒数第i盘寿司最晚吃的时间是n-i*(k+1)+1,最早吃的时间是1.相当于在n个数中选择n/k个数,倒数第i个数的选择范围是(1,n-i*(k+1)+1),且每个数只能被选择一次,使得选择的数的总和最大,因为前面的选择范围更小,我们从前往后选,用线段树找到该范围下最大的寿司的编号,累加,再把这个寿司改成0
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+10;
int T,n,a[N],k,ans;
struct Tree{int maxn,l,r,id;
}t[N*4];
void init()
{ans=0;for(int i=1;i<=4*n;i++)t[i].l=t[i].r=t[i].maxn=t[i].id=0;
}
void build(int p,int l,int r)
{t[p].l=l,t[p].r=r;if(l==r) {t[p].maxn=a[l]; t[p].id=l; return ;}int mid=(l+r)/2;build(p*2,l,mid);build(p*2+1,mid+1,r);if(t[p*2].maxn>t[p*2+1].maxn){t[p].maxn=t[p*2].maxn;t[p].id=t[p*2].id;}else{t[p].maxn=t[p*2+1].maxn;t[p].id=t[p*2+1].id;}
}
int ask(int p,int l,int r)
{if(t[p].l>=l&&t[p].r<=r) return t[p].id;int mid=(t[p].l+t[p].r)/2;int s1=0,s2=0;if(l<=mid) s1=ask(p*2,l,r);if(r>mid) s2=ask(p*2+1,l,r);if(a[s1]>a[s2]) return s1;else return s2;
}
void change(int p,int k)
{if(t[p].l==t[p].r) {t[p].maxn=0; return;}int mid=(t[p].l+t[p].r)/2;if(k<=mid) change(p*2,k);else change(p*2+1,k);if(t[p*2].maxn>t[p*2+1].maxn){t[p].maxn=t[p*2].maxn;t[p].id=t[p*2].id;}else{t[p].maxn=t[p*2+1].maxn;t[p].id=t[p*2+1].id;}
}
void solve()
{ cin>>n>>k;init();for(int i=1;i<=n;i++)cin>>a[i];build(1,1,n);for(int i=n/(k+1);i>=1;i--){int t=ask(1,1,n-i*(k+1)+1);ans+=a[t];change(1,t);}cout<<ans<<endl;
}
signed main()
{std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);cin>>T;while(T--) solve();
}