noip模拟22
A. d
通过两个指针分别计数是选择多少个\(a_i\)小的,剩下的删除\(b_i\)小的,队列维护,记得去重.
A_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS
{
#define p() printf("Pass")
#define ll long long int
#define re register ll
#define lf double
#define lb lower_bound
#define ub upper_bound
#define mp make_pair
#define File(x,y) freopen(#x,"r",stdin),freopen(#y,"w",stdout)
#define fill(x,y) memset(x,y,sizeof x);
#define copy(x,y) memset(y,x,sizeof x);
#define pass() printf("Pass")
inline void read(ll &ss)
{
ss=0; bool cit=0; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=1;
while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
if(cit) ss=-ss;
}
inline void write(ll ss)
{
static int stas[35]; int topps=0;
if(ss<0) putchar('-'),ss=-ss;
do{stas[++topps]=ss%10,ss/=10;}while(ss);
while(topps) putchar(stas[topps--]+48); puts("");
}
} using namespace BSS;
const ll N=1e5+50;
ll m,n,ts;
ll vis[N],visb[N];
struct I { ll id,a,b; } f[N],g[N];
inline bool comp1(I i,I j) { return i.a<j.a; }
inline bool comp2(I i,I j) { return i.b<j.b; }
inline void Work()
{
ll ans=0;
fill(vis,0); fill(visb,0);
sort(g+1,g+1+n,comp1);
sort(f+1,f+1+n,comp2);
// for(ll i=1;i<=n;i++) cout<<g[i].a<<" ";
// cout<<endl;
// for(ll i=1;i<=n;i++) cout<<f[i].b<<" ";
for(ll i=1;i<=m;i++)
{
vis[g[i].id]=1;
}
ll i=1,j=m;
ll maxa=g[j+1].a;
while(i<=n and j>=0)
{
if(!vis[f[i].id])
{
if(visb[g[j].id])
{
j--;
continue;
}
ans=max(ans,maxa*f[i].b);
maxa=g[j].a; vis[g[j].id]=0; vis[f[i].id]=1;
j--; i++;
}
else
{
visb[f[i].id]=1;
i++;
}
}
printf("%lld\n",ans);
return ;
}
signed main()
{
// File(0.in,out);
read(ts);
while(ts--)
{
read(n); read(m);
for(re i=1;i<=n;i++)
{
read(f[i].a); read(f[i].b);
g[i].a=f[i].a; g[i].b=f[i].b;
f[i].id=i; g[i].id=i;
}
Work();
}
return 0;
}
B. e
主席树维护区间.
B_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS {
#define ll long long int
#define ull unsigend ll
#define re register ll
#define lf double
#define mp(x,y) make_pair(x,y)
#define lb lower_bound
#define ub upper_bound
#define File(x,y) freopen(#x,"r",stdin),freopen(#y,"w",stdout)
#define Fill(x,y) memset(x,y,sizeof x)
#define Copy(x,y) memset(x,y,sizeof x)
inline ll read() {
ll ss=0; bool cit=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
return cit?ss:-ss;
}
} using namespace BSS;
const ll N=1e6+55;
ll m,n,ts,tot,cnt,type,alls,lst,z;
ll head[N],val[N],dep[N],fa[N],siz[N],dfn[N],top[N],son[N],rk[N],rt[N];
ll num[N*3],r[N*3],lsh[N*3],id[N*3];
struct I { ll u,v,nxt; } e[N<<1];
struct II { ll ls,rs,sum; } tr[N<<3];
inline ll inc(ll i,ll j){ i+=j; return i>=n ? (i-=n) : i ; }
inline ll dec(ll i,ll j) { i-=j; return i<=0 ? i=(i+n*n)%n : i ; }
inline void add(ll u,ll v){
e[++ts].u=u;
e[ts].v=v;
e[ts].nxt=head[u];
head[u]=ts;
}
inline ll clone(ll pre){
tr[++z]=tr[pre];
return z;
}
inline void pushup(ll x){
tr[x].sum=tr[tr[x].ls].sum+tr[tr[x].rs].sum;
return ;
}
void transit(ll &x,ll pre,ll l,ll r,ll pos){
x=clone(pre);
if(l==r){
tr[x].sum++;
return ;
}
ll mid=(l+r)>>1;
if(pos<=mid) transit(tr[x].ls,tr[pre].ls,l,mid,pos);
else transit(tr[x].rs,tr[pre].rs,mid+1,r,pos);
pushup(x);
return ;
}
void dfs1(ll now,ll dad,ll depth){
fa[now]=dad, dep[now]=depth,
siz[now]=1, val[now]=lb(lsh+1,lsh+1+cnt,val[now])-lsh;
transit(rt[now],rt[dad],1,cnt,val[now]);
for(re i=head[now];i;i=e[i].nxt){
if(e[i].v==dad) continue;
dfs1(e[i].v,now,depth+1);
siz[now]+=siz[e[i].v];
if(siz[son[now]]<siz[e[i].v]){
son[now]=e[i].v;
}
}
return ;
}
void dfs2(ll now,ll high){
dfn[now]=++tot, rk[tot]=now, top[now]=high;
if(!son[now]) return ;
dfs2(son[now],high);
for(re i=head[now];i;i=e[i].nxt){
if(e[i].v==fa[now] or e[i].v==son[now]) continue;
dfs2(e[i].v,e[i].v);
}
return ;
}
ll query_pre(ll x,ll pre,ll l,ll r,ll pos){
if(l==r){
return l;
}
ll mid=(l+r)>>1; ll temp;
if(tr[tr[x].rs].sum-tr[tr[pre].rs].sum<=0)
return query_pre(tr[x].ls,tr[pre].ls,l,mid,pos);
else{
if(tr[tr[x].ls].sum-tr[tr[pre].ls].sum<=0)
return query_pre(tr[x].rs,tr[pre].rs,mid+1,r,pos);
}
if(pos<=mid) return query_pre(tr[x].ls,tr[pre].ls,l,mid,pos);
else{
temp=query_pre(tr[x].rs,tr[pre].rs,mid+1,r,pos);
if(temp>pos) return query_pre(tr[x].ls,tr[pre].ls,l,mid,pos);
else return temp;
}
}
ll query_suf(ll x,ll pre,ll l,ll r,ll pos){
if(l==r){
return l;
}
ll mid=(l+r)>>1; ll temp;
if(tr[tr[x].rs].sum-tr[tr[pre].rs].sum<=0)
return query_suf(tr[x].ls,tr[pre].ls,l,mid,pos);
else{
if(tr[tr[x].ls].sum-tr[tr[pre].ls].sum<=0)
return query_suf(tr[x].rs,tr[pre].rs,mid+1,r,pos);
}
if(pos>=mid+1) return query_suf(tr[x].rs,tr[pre].rs,mid+1,r,pos);
else{
temp=query_suf(tr[x].ls,tr[pre].ls,l,mid,pos);
if(temp<pos) return query_suf(tr[x].rs,tr[pre].rs,mid+1,r,pos);
else return temp;
}
}
inline ll lca(ll x,ll y){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
return x;
}
signed main(){
// File(0.in,out);
n=read(); m=read(); type=read();
ll u,v,w;
for(re i=1;i<=n;i++) lsh[++cnt]=val[i]=read();
for(re i=2;i<=n;i++){
u=read(); v=read();
add(u,v); add(v,u);
}
for(re i=1;i<=m;i++){
lsh[++cnt]=r[i]=read(),num[i]=read();
for(re j=1;j<=num[i];j++){
id[++alls]=read();
}
}
sort(lsh+1,lsh+1+cnt); cnt=unique(lsh+1,lsh+1+cnt)-lsh-1;
dfs1(1,0,1); dfs2(1,1); alls=0; lst=0; ll temp,anor,ans1,ans2,ans;
for(re i=1;i<=m;i++){
r[i]=lb(lsh+1,lsh+1+cnt,r[i])-lsh; ++alls;
id[alls]=inc(id[alls]-1,(lst*type)%n)+1;
anor=id[alls]; ans=1e10;
for(re j=2;j<=num[i];j++){
++alls;
id[alls]=inc(id[alls]-1,(lst*type)%n)+1,
anor=lca(id[alls],anor);
}
for(re j=0;j<num[i];j++){
temp=alls-j;
ans1=query_pre(rt[id[temp]],rt[fa[anor]],1,cnt,r[i]);
ans1=abs(lsh[r[i]]-lsh[ans1]),
ans2=query_suf(rt[id[temp]],rt[fa[anor]],1,cnt,r[i]);
ans2=abs(lsh[r[i]]-lsh[ans2]);
ans=min(ans,min(ans1,ans2));
}
lst=ans;
printf("%lld\n",ans);
}
return 0;
}
C. f
考场上发现每一位对于答案都是独立的,且根据位的先后具有优先性.
发现答案具有单调性,于是选择二分答案.
考虑 \(Meet\ in\ the\ Middle\) 从而对指数进行优化.
C_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS
{
#define ll long long int
#define ull unsigned ll
#define re register ll
#define lf double
#define mp make_pair
#define File(x,y) freopen(#x,"r",stdin),freopen(#y,"w",stdout)
#define fill(x,y) memset(x,y,sizeof x);
#define copy(x,y) memset(y,x,sizeof x);
inline void read(ll &ss)
{
ss=0; bool cit=0; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=1;
while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
if(cit) ss=-ss;
}
inline void write(ll ss)
{
static int stas[35]; int topps=0;
if(ss<0) putchar('-'),ss=-ss;
do{stas[++topps]=ss%10,ss/=10;}while(ss);
while(topps) putchar(stas[topps--]+48); puts("");
}
} using namespace BSS;
const ll N=5e5+50;
ll m,n,rk,tot,ans;
ll a[N],b[N],val[N];
ll sum0[50],sum1[50];// sum0 为异或之前的逆序对个数
struct I { ll cnt,siz,son[2]; } tr[N*64]; // 逆序对个数,子树大小
//inline bool comp(I i,I j) { return i.w==j.w ? i.id<j.id ? i.w>j.w ; }
pair<ll,ll> f1[1<<16],f2[1<<16];
ll que[1<<16];
void Insert(ll now)
{
ll p=0;
for(ll i=30;i>=-1;i--)
{
tr[p].siz++;
if(i==-1) break;
if((now>>i)&1)
{
if(tr[p].son[0]) sum1[i]+=tr[tr[p].son[0]].siz;
if(tr[p].son[1]) p=tr[p].son[1];
else tr[p].son[1]=++tot,p=tot;
}
else
{
if(tr[p].son[1]) sum0[i]+=tr[tr[p].son[1]].siz;
if(tr[p].son[0]) p=tr[p].son[0];
else tr[p].son[0]=++tot,p=tot;
}
}
return ;
}
inline bool check(ll x)
{
ll temp=0;
ll j=(1<<(m-m/2))-1;
for(ll i=0;i<(1<<m/2) and f1[i].first<=x;i++)
{
while(f1[i].first+f2[j-1].first>=x and j>=0)
{
j--;
}
temp+=j;
}
if(temp>=rk) return 0;
else return 1;
//如果逆序对个数比 x 小的状态种类数大于 rk,那么就让 x 变小
}
inline ll getans()
{
ll temp=0; ll j=(1<<(m-m/2))-1;
ll cnt=0; fill(que,0);
for(ll i=0;i<(1<<m/2) and f1[i].first<=ans;i++)
{
while(f1[i].first+f2[j-1].first>ans and j>=0)
{
j--;
}
temp+=j;
if(f1[i].first+f2[j-1].first==ans)
{
que[++cnt]=f2[j-1].second<<(m/2)|f1[i].second;
}
}
sort(que+1,que+1+cnt);
for(ll i=temp;i>=0 and cnt>=0;i--,cnt--)
{
if(i==rk)
{
return que[cnt];
}
}
return 0;
}
signed main()
{
// File(0.in,out);
read(n); read(m); read(rk);
if(m==0)
{
printf("0 0");
return 0;
}
for(ll i=1;i<=n;i++)
{
read(val[i]);
Insert(val[i]);
}
for(ll i=0;i<(1<<m/2);i++)
{
for(ll j=0;j<m/2;j++)
{
if((i>>j)&1) f1[i].first+=sum1[j];
else f1[i].first+=sum0[j];
}
f1[i].second=i;
}
for(ll i=0;i<(1<<(m-m/2));i++)
{
for(ll j=0;j<=m-m/2;j++)
{
if((i>>j)&1) f2[i].first+=sum1[j+m/2];
else f2[i].first+=sum0[j+m/2];
}
f2[i].second=i;
}
sort(f1,f1+(1<<m/2));
sort(f2,f2+(1<<(m-m/2)));
ll le=0,ri=(n-1)*n/2,mid;
// 二分逆序对个数
// 求出排名为 rk 的逆序对究竟有多少个
while(le<=ri)
{
mid=(le+ri)>>1;
if(check(mid)) le=mid+1;
else ri=mid-1;
}
ans=ri;
printf("%lld %lld",ans,getans());
return 0;
}