UNR2023
UNR唯数不多的能切掉的两道题目(其中有一题还犯傻被卡常了,中间还过了两发QWQ)
DAY1 T1
题意:两位玩家,小青鱼和空间的使者,将轮流进行操作。在每一轮中,玩家可以从序列中选择任意两个相邻的元素并将它们删除。删除后,这两个元素两侧的剩余序列将会自动合并。这样的操作将持续进行,直到序列中只剩下一个元素。
在这场游戏中,小青鱼是先手。他的目标是在游戏结束时让剩下的那个整数尽可能的大,而智者则希望让最后剩下的整数尽可能小。最后剩下什么?
这题很像吴畅那个神秘题啊,但是判定条件简单一些.首先我们考虑二分一个答案,把大于等于这个数的赋成$2$,小于的赋成$1$.
我们接着考虑最后一步是谁操作(起码我的做法要分情况讨论,大部分神奔不需要)
我们考虑最后是智者,那么我们知道如果最后留给智者的是$212$.那么小青鱼一定可以留下答案.我们考虑判定条件:我们每次是删除两个数,也就是原本$12$数的位置的奇偶不变,我们就知道小青鱼一定要把奇数位置的$1$删除,这样就一定能获胜.
如果最后是小青鱼操作,那么如果智者给小青鱼留下了$121$则一定可以删除答案,所以智者要把奇数位置的$2$删完.然后就做完了.
#include<bits/stdc++.h>
using namespace std;
namespace FastIO {
char buf[1<<21], *p1=buf, *p2=buf;
inline int getch (void) {
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;
}
inline int read (void) {
int x = 0, f = 1, ch = getch();
while(!isdigit(ch)) {
if(ch == '-') f = -f;
ch = getch();
}
while(isdigit(ch)) {
x = x * 10 + ch - '0';
ch = getch();
}
return x * f;
}
char buf2[1<<21], buf3[25];
int tp_l, buf2_l=-1;
inline void flush (void) {
fwrite (buf2, 1, buf2_l+1, stdout), buf2_l=-1;
}
inline void print (int x, char ch=10) {
if(buf2_l>(1<<20)) flush();
if(x<0) buf2[++buf2_l]='-', x=-x;
do buf3[++tp_l]=x%10+48;
while(x/=10);
do buf2[++buf2_l]=buf3[tp_l];
while(--tp_l);
buf2[++buf2_l] = ch;
}
}
using FastIO::read;
using FastIO::print;
int a[1000050],b[1000005],ans,flag,num,n,t,mn;
int st[1000050],cnt=0;
bool check1(int x){
for(int i=1;i<=n;i++){
if(a[i]>=x)b[i]=2;
else b[i]=1;
}
int ss=0;
for(int i=1;i<=n;i++){
if((i%2==1)&&b[i]==1){
ss++;i++;
}
}
if(ss<=num/2)return 1;
return 0;
}
bool check2(int x){
for(int i=1;i<=n;i++){
if(a[i]>=x)b[i]=2;
else b[i]=1;
}
int ss=0;
for(int i=1;i<=n;i++){
if((i%2==1)&&b[i]==2){
ss++;i++;
}
}
if(ss<=num/2)return 1;
return 0;
}
int main(){
// freopen("A.in","r",stdin);
// freopen("A.out","w",stdout);
t=read();
while(t--){
n=read();mn=n+1;
for(int i=1;i<=n;i++){
a[i]=read();
mn=min(mn,a[i]);
}
num=n/2;flag=num%2;
int l=1,r=n,ans=mn;
if(flag==0){
while(l<=r){
int mid=(l+r)/2;
if(check1(mid)){
ans=mid;
l=mid+1;
}else {
r=mid-1;
}
}
}else {
while(l<=r){
int mid=(l+r)/2;
if(check2(mid)){
r=mid-1;
}else {
ans=mid;
l=mid+1;
}
}
}
printf("%d\n",ans);
}
FastIO::flush();
return 0;
}
关于DAY1 T2我自己的做法就是每长度为$16$为一块,然后暴力把每种的最优答案跑出来直接拼起来.
但是WT直接把长度小于等于$576$的直接贪心bitset匹配找到最长的,然后过了!很厉害.
DAY2 T1
这题赛时竟然想出来了,但是抽象的我被卡常了.
首先有一个包的暴力是$k=1$,这一部分直接从后到前扫描线,每次看当前这个位置最多能存活多久,这个直接二分+RMQ(区间$a$的最大值),然后直接线段树区间覆盖.
对于每个询问[l,r]我们挂在$l$上,然后查询线段树上$r$的位置的值.
对于正解这题有个我们需要自己手玩一下发现一些性质,我们发现一个区间选$k$个数,$b$值前$k-1$大的肯定会选,具体的我们考虑若当前只有前$k-2$大的,那么碰到$k-1$大的时候一定会把其中一个弹出,并前后面总弹出最小的那个$b$.
所以我们先用主席树把这前$k-1$的$c$加起来,接着我们考虑还会有个什么?
首先我们找到$[l,r]$区间中,$b$值前$k$大的数最靠后面的那个位置$pos$.如果从$l$做到$pos$,我们发现那个特殊的数一定是$b$值为第$k$大的,因为在$pos$时一定会把最小的$b$弹出,前面也是一样的.
所以我们可以找出$b$值第$k$大的数,这个可以主席树上二分,至于最远的位置,我赛时脑子一抽,写了个$2log$二分+区间求和(被卡常,但是能过).其实可以扫描线+树状数组单$log$解决.
对于$[pos+1,r]$其实做法就是$k=1$的情况,只不过扫描线到$l$的时候还需要判断一下那个$b$值第$k$大的数的存活情况(直接二分就行)
于是就做完了,我太乐了,DAY2会题却比DAY1考的垃圾,果然还是要打暴力.
提供单$log$不卡常代码:
#include<bits/stdc++.h>
using namespace std;
namespace FastIO {
char buf[1<<21], *p1=buf, *p2=buf;
inline int getch (void) {
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;
}
inline int read (void) {
int x = 0, f = 1, ch = getch();
while(!isdigit(ch)) {
if(ch == '-') f = -f;
ch = getch();
}
while(isdigit(ch)) {
x = x * 10 + ch - '0';
ch = getch();
}
return x * f;
}
char buf2[1<<21], buf3[25];
int tp_l, buf2_l=-1;
inline void flush (void) {
fwrite (buf2, 1, buf2_l+1, stdout), buf2_l=-1;
}
inline void print (int x, char ch=10) {
if(buf2_l>(1<<20)) flush();
if(x<0) buf2[++buf2_l]='-', x=-x;
do buf3[++tp_l]=x%10+48;
while(x/=10);
do buf2[++buf2_l]=buf3[tp_l];
while(--tp_l);
buf2[++buf2_l] = ch;
}
}
using FastIO::read;
using FastIO::print;
int n,qq;
struct stu{
int a,b,c;
}s[500005];
struct node{
int l,r,k,id,val;
}q[500005];
long long ans[500005];
int root[500005],pos[500005];
vector<int>g[500005],p[500005];
struct tree{
int lc,rc,num,mx;
long long sum;
}t[12000000];
int tot,po,ls;
void xg(int &k,int k1,int l,int r,int pos,int v1,int v2){
k=++tot;
t[k]=t[k1];
t[k].num+=v1;
t[k].sum+=v2;
if(l==r&&l==pos)return;
int mid=(l+r)>>1;
if(pos<=mid)xg(t[k].lc,t[k1].lc,l,mid,pos,v1,v2);
else xg(t[k].rc,t[k1].rc,mid+1,r,pos,v1,v2);
}
long long query(int k1,int k2,int l,int r,int k){
if(l==r){ls=pos[l];return t[k2].sum-t[k1].sum;}
int gs=t[t[k2].rc].num-t[t[k1].rc].num;
int mid=(l+r)>>1;
if(gs>=k){
return query(t[k1].rc,t[k2].rc,mid+1,r,k);
}else {
return t[t[k2].rc].sum-t[t[k1].rc].sum+query(t[k1].lc,t[k2].lc,l,mid,k-gs);
}
}
int query1(int k1,int k2,int l,int r,int L){
if(l>=L)return t[k2].num-t[k1].num;
int mid=(l+r)/2;
if(L<=mid)return query1(t[k1].rc,t[k2].rc,mid+1,r,L)+query1(t[k1].lc,t[k2].lc,l,mid,L);
return query1(t[k1].rc,t[k2].rc,mid+1,r,L);
}
struct szsz{
int c[500005];
int lowbit(int x){
return x&(-x);
}
void xg(int i,int val){
for(;i;i-=lowbit(i))c[i]=max(c[i],val);
}
int query(int i){
int res=0;
for(;i<=n;i+=lowbit(i))res=max(res,c[i]);
return res;
}
}t1;
namespace RMQ{
int logg[500005],mx[21][500005];
void ycl(){
logg[0]=(-1);
for(int i=1;i<=n;i++){
logg[i]=logg[i>>1]+1;
mx[0][i]=s[i].a;
}
for(int j=1;j<=logg[n];j++){
for(int i=1;i+(1<<j)-1<=n;i++){
mx[j][i]=max(mx[j-1][i],mx[j-1][i+(1<<(j-1))]);
}
}
return;
}
int query(int l,int r){
if(l>r)return 0;
int c=logg[r-l+1];
return max(mx[c][l],mx[c][r-(1<<c)+1]);
}
}
struct segment{
int mn[500005*4];
void pushdown(int k){
if(mn[k]){
mn[k<<1]=mn[k];mn[k<<1|1]=mn[k];mn[k]=0;
}
}
void xg(int k,int l,int r,int L,int R,int id){
if(l>=L&&r<=R){
mn[k]=id;
return;
}
int mid=(l+r)/2;
pushdown(k);
if(L<=mid)xg(k<<1,l,mid,L,R,id);
if(R>mid)xg(k<<1|1,mid+1,r,L,R,id);
}
int query(int k,int l,int r,int pos){
if(l==r&&l==pos)return mn[k];
int mid=(l+r)>>1;
pushdown(k);
if(pos<=mid)return query(k<<1,l,mid,pos);
else return query(k<<1|1,mid+1,r,pos);
}
}t2;
int main(){
// freopen("A.in","r",stdin);
// freopen("A.out","w",stdout);
n=read();qq=read();
for(int i=1;i<=n;i++){
s[i].a=read();
}
for(int i=1;i<=n;i++){
s[i].b=read();
pos[s[i].b]=i;
}
for(int i=1;i<=n;i++){
s[i].c=read();
}
for(int i=1;i<=n;i++){
xg(root[i],root[i-1],1,n,s[i].b,1,s[i].c);
}
for(int i=1;i<=qq;i++){
q[i].l=read();q[i].r=read();q[i].k=read();
q[i].id=i;
po=q[i].l-1;
if(q[i].k-1>=1){
ans[i]=query(root[q[i].l-1],root[q[i].r],1,n,q[i].k-1);
query(root[q[i].l-1],root[q[i].r],1,n,q[i].k);
q[i].r=q[i].r;q[i].val=ls;
p[q[i].r].push_back(i);
}else {
q[i].l=po+1;q[i].val=0;
}
}
for(int i=1;i<=n;i++){
t1.xg(s[i].b,i);
for(int j=0;j<p[i].size();j++){
int id=p[i][j];
q[id].l=t1.query(s[q[id].val].b)+1;
}
}
for(int i=1;i<=qq;i++){
if(q[i].l>q[i].r){
ans[i]+=s[q[i].val].c;
continue;
}
g[q[i].l].push_back(i);
}
RMQ::ycl();
for(int i=n;i>=1;i--){
int l=i,r=n,ss=i;
while(l<=r){
int mid=(l+r)>>1;
if(s[i].b>RMQ::query(i+1,mid)){
ss=mid;l=mid+1;
}else r=mid-1;
}
t2.xg(1,1,n,i,ss,i);
for(int j=0;j<g[i].size();j++){
int id=g[i][j];
int val=q[id].val;
if(val==0){
int num=t2.query(1,1,n,q[id].r);
ans[id]=ans[id]+s[num].c;
continue;
}
l=i,r=n,ss=i-1;
while(l<=r){
int mid=(l+r)>>1;
if(s[val].b>RMQ::query(i,mid)){
ss=mid;l=mid+1;
}else r=mid-1;
}
if(ss>=q[id].r){
ans[id]=ans[id]+s[val].c;
}else {
int num=t2.query(1,1,n,q[id].r);
ans[id]=ans[id]+s[num].c;
}
}
}
for(int i=1;i<=qq;i++){
printf("%lld\n",ans[i]);
}
FastIO::flush();
return 0;
}


浙公网安备 33010602011771号