1. 程式人生 > 其它 >noip模擬22[d·e·f]

noip模擬22[d·e·f]

\(noip模擬22\;solutions\)

哈哈哈,這次暴力打滿直接190,其實不到哈哈哈,187.。

這次的題暴力極其好打,但是正解確實不簡單。。。

打了好久才改完這個題,改完的時候爽暴了

這些一個字母的題就非常的迷人,題面很短,題目很難,但是拿分還是挺簡單的

·

\(T1\;d\)

就這個題考場一小時切掉,還是慢了點

這個就是一個排序加上,瘋狂彈,

就是一個按照a排序,一個按照b排序

我們知道一定要刪去小的,所以我們就。。。。

我們先刪掉m個a中的a較小的矩形,然後我們就開始一個一個往回拿。

肯定我們要拿回來最大的,然後刪掉一個b最小的,

我們這裡要判斷這個b有沒有被刪過,所以我們要加個while

如果刪掉的a的id的b比當前的b小,那就直接刪掉。。。

看程式碼

AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int 
#define ll long long
const int N=1e5+5;
int T,n,m;
struct mtr{
	int a,b,id;
	bool operator < (mtr x)const{
		if(b!=x.b)return b<x.b;
		if(a!=x.a)return a<x.a;
		return id<x.id;
	}
}xa[N],xb[N];
ll ans;
bool via[N],vib[N];
bool cmpa(mtr x,mtr y){
	if(x.a!=y.a)return x.a<y.a;
	if(x.b!=y.b)return x.b<y.b;
	return x.id<y.id;
}
bool cmpb(mtr x,mtr y){
	if(x.b!=y.b)return x.b<y.b;
	if(x.a!=y.a)return x.a<y.a;
	return x.id<y.id;
}
signed main(){
	scanf("%d",&T);
	while(T--){
		scanf("%d%d",&n,&m);
		for(re i=1;i<=n;i++){
			scanf("%d%d",&xa[i].a,&xa[i].b);
			xa[i].id=i;xb[i]=xa[i];
		}
		sort(xa+1,xa+n+1,cmpa);
		sort(xb+1,xb+n+1,cmpb);
		//if(xb[1]<xb[2])cout<<"sb"<<endl;
		for(re i=1;i<=m;i++)via[xa[i].id]=true;
		int j=1;
		while(via[xb[j].id])j++;
		ans=1ll*xa[m+1].a*xb[j].b;
		//cout<<xa[m+1].id<<" "<<xb[j].id<<endl;
		for(re i=m;i>=1;i--){
			via[xa[i].id]=false;
			if(xa[i]<xb[j]){
				ans=max(ans,1ll*xa[i+1].a*xb[j].b);
				//cout<<xa[i].a<<" "<<xb[j].b<<endl;
				continue;
			}
			j++;
			while(via[xb[j].id])j++;
			ans=max(ans,1ll*xa[i].a*xb[j].b);
		}
		printf("%lld\n",ans);
	}
}

·

\(T2\;e\)

考場暴力向上跳,跳出來80pts,為啥只有這麼些分呢,因為沒加快讀,加上快讀89,這是暴力的極限了

所以正解是主席樹,以樹上的關係為歷史版本,他的爹是他的前一版本

然後直接找到共同的lca,分別找到k條鏈上的比r大的最小值,比r小的最大值

我們就找到了答案,所以我調了3個小時,為啥??因為我有一個數組越界了

為啥越界呢?因為我有一個計數器用了兩次,加爆了,所以也不給我說段錯誤

只有一個錯誤的答案,導致我從昨天晚上一直調到了今天上午8:18

AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
const int N=1e5+5;
int n,q,typ,p[N*3],a[N];
int to[N*2],nxt[N*2],head[N],rp;
int lsh[N*4],lh;
void add_edg(int x,int y){
	to[++rp]=y;
	nxt[rp]=head[x];
	head[x]=rp;
}
struct ZXS{
	int ls[N*80],rs[N*80];
	int siz[N*80];
	int seg;
	void ins(int pre,int &x,int l,int r,int pos){
		x=++seg;
		siz[x]=siz[pre];
		siz[x]+=1;
		if(l==r)return ;
		int mid=l+r>>1;
		if(pos<=mid)rs[x]=rs[pre],ins(ls[pre],ls[x],l,mid,pos);
		else ls[x]=ls[pre],ins(rs[pre],rs[x],mid+1,r,pos);
		return ;
	}
	int query_min(int pre,int x,int l,int r,int ql,int qr){
		//cout<<x<<" "<<l<<" "<<r<<" "<<ql<<" "<<qr<<" "<<siz[ls[x]]<<" "<<siz[ls[pre]]<<endl;
		//if(!x)return -1;
		//if(ql>r||qr<l)return -1;
		if(l==r)return l;
		int mid=l+r>>1,ret=-1;
		if(ls[x]!=ls[pre]&&ql<=mid)ret=query_min(ls[pre],ls[x],l,mid,ql,qr);
		if(rs[x]!=rs[pre]&&qr>mid&&ret==-1)ret=query_min(rs[pre],rs[x],mid+1,r,ql,qr);
		return ret;
	}
	int query_max(int pre,int x,int l,int r,int ql,int qr){
		//cout<<x<<" "<<l<<" "<<r<<" "<<ql<<" "<<qr<<endl;
		//if(!x)return -1;
		//if(ql>r||qr<l)return -1;
		if(l==r)return l;
		int mid=l+r>>1,ret=-1;
		if(rs[x]!=rs[pre]&&qr>mid)ret=query_max(rs[pre],rs[x],mid+1,r,ql,qr);
		if(ls[x]!=ls[pre]&&ql<=mid&&ret==-1)ret=query_max(ls[pre],ls[x],l,mid,ql,qr);
		return ret;
	}
}zxs;
int rt[N],ans;
int dfn[N],cnt,idf[N],fa[N];
int siz[N],son[N],top[N],dep[N];
void dfs1(int x){
	siz[x]=1;son[x]=0;
	a[x]=lower_bound(lsh+1,lsh+lh+1,a[x])-lsh;
	zxs.ins(rt[fa[x]],rt[x],1,lh,a[x]);
	for(re i=head[x];i;i=nxt[i]){
		int y=to[i];
		if(y==fa[x])continue;
		fa[y]=x;dep[y]=dep[x]+1;
		dfs1(y);siz[x]+=siz[y];
		if(!son[x]||siz[y]>siz[son[x]])son[x]=y;
	}
}
void dfs2(int x,int f){
	dfn[x]=++cnt;idf[cnt]=x;
	top[x]=f;
	if(son[x])dfs2(son[x],f);
	for(re i=head[x];i;i=nxt[i]){
		int y=to[i];
		if(y==son[x]||y==fa[x])continue;
		dfs2(y,y);
	}
}
int LCA(int x,int y){
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]])swap(x,y);
		x=fa[top[x]];
	}
	return dep[x]<dep[y]?x:y;
}
int r[N*3],k[N*3],ll[N*3],rr[N*3],tot;
signed main(){
	scanf("%d%d%d",&n,&q,&typ);
	for(re i=1;i<=n;i++)scanf("%d",&a[i]),lsh[++lh]=a[i];
	for(re i=1,x,y;i<n;i++){
		scanf("%d%d",&x,&y);
		add_edg(x,y);add_edg(y,x);
	}
	//for(re i=1;i<=n;i++)cout<<rt[i]<<" ";
	for(re i=1;i<=q;i++){
		scanf("%d%d",&r[i],&k[i]);
		ll[i]=tot+1;
		for(re j=1;j<=k[i];j++)scanf("%d",&p[++tot]);
		rr[i]=tot;
		lsh[++lh]=r[i];
	}
	sort(lsh+1,lsh+lh+1);
	lh=unique(lsh+1,lsh+lh+1)-lsh-1;
	//cout<<"lh :"<<lh<<endl;
	dfs1(1);dfs2(1,1);
	//for(re i=1;i<=n;i++)cout<<rt[i]<<" ";
	int lans=0;
	for(re i=1;i<=q;i++){
		int lca=0;ans=0x3f3f3f3f;
		//cout<<k[i]<<endl;
		for(re j=ll[i];j<=rr[i];j++){
			p[j]=(p[j]-1+lans*typ)%n+1;
			if(j==ll[i])lca=p[j];
			else lca=LCA(lca,p[j]);
			//cout<<j<<" "<<"finish lca"<<endl;
		}
		//cout<<i<<" lca: "<<lca<<endl;
		//cout<<i<<" "<<"finish lca"<<endl;
		r[i]=lower_bound(lsh+1,lsh+lh+1,r[i])-lsh;
		for(re j=ll[i];j<=rr[i];j++){
			int tmp1=zxs.query_min(rt[lca],rt[p[j]],1,lh,r[i],lh);
			//cout<<"finish min"<<" "<<j<<endl;
			int tmp2=zxs.query_max(rt[lca],rt[p[j]],1,lh,1,r[i]);
			//cout<<"finish max"<<" "<<j<<endl;
			//cout<<r[i]<<" "<<tmp1<<" "<<tmp2<<" "<<j<<endl;
			//cout<<i<<" "<<"finish query"<<" "<<p[j]<<endl;
			if(tmp1!=-1)ans=min(ans,lsh[tmp1]-lsh[r[i]]);
			if(tmp2!=-1)ans=min(ans,lsh[r[i]]-lsh[tmp2]);
		}
		ans=min(ans,abs(lsh[a[lca]]-lsh[r[i]]));
		lans=ans;
		printf("%d\n",ans);
	}
}

·

\(T3\;f\)

這個題直接告訴我一個訊息,遇到和位運算有關的東西,首先想trie樹

這個題也是在trie樹上實現的,首先我們發現,每一位的貢獻是互不影響的

一個數對答案的貢獻就是他對應的子樹的另外那顆子樹的大小,0就是1,1就是0

為什麼,我們按照位置順序插入,那麼後插入的如果值比先插入的小

他們一定會有一個最高不一樣的位,我們就在這一位統計貢獻

然而我們不可以每次都重新插入一遍,你會比樹狀陣列T的更慘

我們發現,如果xor的那個x某一位是1的話,就是把這兩顆子樹交換一下,那麼此時的貢獻就是原樹上在1找0的個數

如果是0,那就反過來。如此我們就可以\(O(2^klogn)\)解決掉前幾個點

但是還不夠,我們還要繼續優化,meet in the middle 對,沒錯,從中間拆開

分為前\(\frac{k}{2}\)個和後\(\frac{k}{2}\)個,這樣的話,複雜度就在可控範圍內了

第一問,我們二分這個逆序對個數,判斷函式裡面是一個雙指標,這個自己看程式碼吧,因為解釋不清楚

第二問和第一問一樣,也是雙指標,只不過這次我們統計相等的情況而不是小於等於,這裡開個vector來存有那些數可以到這個大小

最後輸出就完事了。。。

AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int 
#define ll long long
#define fi first
#define se second
const int N=5e5+5;
int n,k,p,a[N];
int k1,k2,s1,s2;
ll gx[35][2],ans1,ans2;
int rt;
struct TRIE{
	ll siz[N*35];
	int seg;
	int son[N*35][2];
	void ins(int &x,int v,int dep){//dep 30 less
		if(!x)x=++seg;
		siz[x]++;
		if(dep<0)return ;
		int tmp=v>>dep&1;
		gx[dep][tmp]+=siz[son[x][tmp^1]];
		ins(son[x][tmp],v,dep-1);
	}
}t;
pair<long long,int> f1[N*2],f2[N*2];
int check(ll x){
	ll ret=0,j=s2;
	for(re i=1;i<=s1;i++){
		while(f2[j].fi+f1[i].fi>x&&j>0)j--;
		ret+=j;
	}
	return ret;
}
vector<int> ji;
signed main(){
	scanf("%d%d%d",&n,&k,&p);
	if(k==0){
		cout<<"0 0"<<endl;
		return 0;
	}
	for(re i=1;i<=n;i++)scanf("%d",&a[i]),t.ins(rt,a[i],30);
	k1=k>>1;k2=k-k1;
	s1=1<<k1;s2=1<<k2;
	for(re i=0;i<(1<<k1);i++){
		ll tmp=0;
		for(re j=0;j<k1;j++)
			tmp+=gx[j][i>>j&1];
		f1[i+1].fi=tmp;
		f1[i+1].se=i;
	}
	//ll as=f1[1];
	sort(f1+1,f1+s1+1);
	for(re i=0;i<(1<<k2);i++){
		ll tmp=0;
		for(re j=0;j<k2;j++)
			tmp+=gx[j+k1][i>>j&1];
		f2[i+1].fi=tmp;
		f2[i+1].se=i;
	}
	//cout<<as+f2[1]<<endl;
	sort(f2+1,f2+s2+1);
	ll l=0,r=1ll*n*(n-1)/2;
	while(l<r){
		ll mid=l+r>>1;
		if(check(mid)<p)l=mid+1;
		else r=mid;
	}ans1=l;
	//cout<<"finish first"<<" "<<ans1<<endl;
	ll bas=check(ans1-1),j=s2;
	//cout<<bas<<endl;
	for(re i=1;i<=s1;i++){
		int tmp;
		while(f2[j].fi+f1[i].fi>ans1)j--;
		tmp=j;
		while(f2[j].fi+f1[i].fi==ans1&&j>0){
			ji.push_back(f1[i].se+(f2[j].se<<k1));
			j--;
		}
		j=tmp;
	}
	sort(ji.begin(),ji.end());
	ans2=ji[p-bas-1];
	printf("%lld %lld",ans1,ans2);
}