noi.ac上的做题记录

记录了从20.2.14至20.2.23在noi.ac的做题记录,总计11题。

1、#1508.三位偏序
寒假学过的CDQ算法的模板题,温习了一遍。
CDQ算法流程可以理解为:
先以第一维为第一关键字排序。
由于对于第\(i\)个元素,只有它之前的元素才能对它产生贡献,所以维护以第二维为关键字的树状数组,从前到后找第二维比他小的元素。
如何保证第二维有序呢?可以采用基于分治思想的归并排序,关键字为第二维。
考虑一个子问题,需要排序的序列的左右两个以中心元素为分界线的子序列已经有序。由于左子序列的第一维全部比右子序列小,所以只有左子序列可以对它产生贡献。
所以直接归并排序,左右各维护一个指针扫即可。最后答案即为贡献之和。
\(code\):

/********************************
    This code is made by ghy.
    Oj: noi.ac
    Language: C++
    Status: AC
    Complexity: O(nlognlogk)
********************************/
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#include <set>
#include <utility>
#include <cctype>
#include <stack>
#define il inline
#define ll long long
#define rg register
#define mp(a,b) make_pair(a,b);
#define pb(a) push_back(a);
#define mst(a,b) memset(a,b,sizeof a) 
using namespace std;
il int read(){
	rg int x=0,f=1; rg char c=getchar();
	while(c<'0' || c>'9'){
		if(c=='-') f=-1; c=getchar();
	}
	while(c>='0' && c<='9'){
		x=(x<<1)+(x<<3)+(c^48); c=getchar();
	}
	return x*f;
}

const int Inf1=0x3f3f3f3f;
const int Inf2=1e9;
const int mod=1e9+7;
const int N=2e5+5;
int n,ccnt,k,numm;
int ans[N],bit[N];
struct Flower{
	int a,b,c,num,cnt;
}f[N],cdq[N];

il bool cmp1(Flower f1,Flower f2){
	return f1.a==f2.a?f1.b==f2.b?f1.c<f2.c:f1.b<f2.b:f1.a<f2.a;
}

il bool cmp2(Flower f1,Flower f2){
	return f1.b==f2.b?f1.c<f2.c:f1.b<f2.b;
}

il int lowbit(int x){
	return x&(-x);
}

il void add(int x,int val){
	while(x<=k){
		bit[x]+=val;
		x+=lowbit(x);
	}
}

il int sum(int x){
	int ret=0;
	while(x){
		ret+=bit[x];
		x-=lowbit(x);
	}
	return ret;
}

il void CDQ(int l,int r){
	if(l==r)
		return;
	int mid=(l+r)>>1;
	CDQ(l,mid);
	CDQ(mid+1,r);
	sort(cdq+l,cdq+mid+1,cmp2);
	sort(cdq+mid+1,cdq+r+1,cmp2);
	int pnt1=l,pnt2;
	for(pnt2=mid+1;pnt2<=r;++pnt2){
		while(cdq[pnt1].b<=cdq[pnt2].b && pnt1<=mid){
			add(cdq[pnt1].c,cdq[pnt1].num);
			++pnt1;
		}
		cdq[pnt2].cnt+=sum(cdq[pnt2].c);
	}
	for(rg int i=l;i<pnt1;++i)
		add(cdq[i].c,-cdq[i].num);
}

int main(){
	n=read();
	k=read();
	for(rg int i=1;i<=n;++i){
		f[i].a=read();
		f[i].b=read();
		f[i].c=read();
	}
	sort(f+1,f+n+1,cmp1);
	for(rg int i=1;i<=n;++i){
		++numm;
		if(f[i].a!=f[i+1].a || f[i].b!=f[i+1].b || f[i].c!=f[i+1].c){
			++ccnt;
			cdq[ccnt].a=f[i].a;
			cdq[ccnt].b=f[i].b;
			cdq[ccnt].c=f[i].c;
			cdq[ccnt].num=numm;
			numm=0;
		}
	}
	CDQ(1,ccnt);
	for(rg int i=1;i<=ccnt;++i)
		ans[cdq[i].cnt+cdq[i].num-1]+=cdq[i].num;
	for(rg int i=0;i<n;++i)
		printf("%d\n",ans[i]);
	return 0;
}

2、#1465.青蛙的约会
exgcd的题目,复习了一下。设跳k次后相遇,则\((x+mk)\)%\(L\)=\((y+nk)\)%\(L\)。直接用exgcd套即可。
值得注意的一点是,我起初把exgcd函数定为了int型,但先返回了数据,函数结束了才进行了修改。起初没意识到这一点,只有50分,后来才改对。
\(code:\)

/********************************
    This code is made by ghy.
    Oj: noi.ac
    Language: C++
    Status: AC
    Complexity: O(log^2n)
********************************/
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#include <set>
#include <utility>
#include <map>
#include <cstdlib>
#include <ctime>
#define il inline
#define ll long long
#define rg register
#define mp(a,b) make_pair(a,b);
#define pb(a) push_back(a);
#define mst(a,b) memset(a,b,sizeof a) 
using namespace std;
il ll read(){
	rg ll x=0,f=1; rg char c=getchar();
	while(c<'0' || c>'9'){
		if(c=='-') f=-1; c=getchar();
	}
	while(c>='0' && c<='9'){
		x=(x<<1)+(x<<3)+(c^48); c=getchar();
	}
	return x*f;
}

const int Inf1=0x3f3f3f3f;
const int Inf2=1e9;
const int mod=1e9+7;

il ll exgcd(ll a,ll b,ll &x,ll &y){
    if(!b){
        x=1;
		y=0;
        return a;
    }
    ll ans=exgcd(b,a%b,x,y);
    ll tmp=x;
    x=y;
	y=tmp-a/b*y;
	return ans;
}

int main(){
    ll x=read();
	ll y=read();
	ll a=x-y;
	ll m=read();
	ll n=read();
	ll b=n-m;
	ll l=read();
    if(b<0){
		b=-b;
		a=-a;
	}
	ll x1=0,y1=0;
	ll ans=exgcd(b,l,x1,y1);
    ll mod=l/ans;
    if(a%ans!=0)
		puts("Impossible");
    else
		printf("%lld\n",(x1*(a/ans)%mod+mod)%mod); 
    return 0;
}

3、#1415.宠物收养所
复习了一遍set的用法。
观察到,任意时间,在店内的只有可能全是人或全是宠物。既可以人找宠物,也可以宠物找人。
所以我们可以记一下当前是什么。如果与当前店中的一样,就直接加入。反之,就找前驱或后继知道匹配为止。
\(code:\)

/******************************
    This code is made by ghy.
    Oj: noi.ac
    Language: C++
    Status: AC
    Complexity: O(nlogn) 
*****************************/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <map>
#include <set>
#include <bitset>
#include <utility>
#include <ctime>
#define ll long long
#define rg register
#define il inline
#define pb(a) push_back(a)
#define File(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
#define mst(a,b) memset(a,b,sizeof a)
#define mp(a,b) make_pair(a,b)
#define smallrootpile priority_queue <int,vector<int>,greater<int> >
#define bigrootpile priority_queue <int>
using namespace std;
il int read(){
    rg int x=0,f=1; rg char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-') f=-1; c=getchar();
    }
    while(c>='0'&&c<='9'){
        x=(x<<1)+(x<<3)+(c^48); c=getchar();
    }
    return x*f;
}

const int Inf1=0x3f3f3f3f;
const int Inf2=1e9,mod=1e6;
set <int> s;
set <int> :: iterator l,r;
int n,x,y,opt;
ll ans;

il void find(int x){
	l=--s.lower_bound(x);
	r=s.lower_bound(x);
	if((x-*l)<=(*r-x) && (*l!=-Inf2)){
		ans=(ans+x-*l)%mod;
		s.erase(l);
	}
	else{
		ans=(ans+*r-x)%mod;
		s.erase(r);
	}
}

int main(){
	s.insert(-Inf2);
	s.insert(Inf2);
    n=read();
	while(n--){
		x=read();
		y=read();
		if(s.size()==2){
			opt=x;
			s.insert(y);
		}
		else if(x==opt)
			s.insert(y);
		else
			find(y);
	}
	printf("%lld\n",ans);
    return 0;
}

4、#42.\(queen\)
先将皇后以行为第一关键字,列为第二关键字排序。
考虑新加入一个皇后。
如果行上已有皇后,且无皇后继续加入,即排序后下一个皇后为下一行,则做贡献的只有左侧的一个皇后。
如果行上已有皇后,且有皇后继续加入,即排序后下一个皇后为本行,则左右两侧的侧的皇后都做贡献。
如果行上暂无皇后,标记行为已有皇后,若无皇后加入,则贡献为\(0\)。反之则为1。
列亦然,对角线亦然。只要判断左右对角线。注意对角线相同的坐标和也相同。
\(code\):

/********************************
    This code is made by ghy.
    Oj: noi.ac
    Language: C++
    Status: AC
    Complexity: O(mlogm)
********************************/
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#include <set>
#include <utility>
#include <map>
#include <cstdlib>
#include <ctime>
#define il inline
#define ll long long
#define rg register
#define mp(a,b) make_pair(a,b);
#define pb(a) push_back(a);
#define mst(a,b) memset(a,b,sizeof a) 
using namespace std;
il int read(){
	rg int x=0,f=1; rg char c=getchar();
	while(c<'0' || c>'9'){
		if(c=='-') f=-1; c=getchar();
	}
	while(c>='0' && c<='9'){
		x=(x<<1)+(x<<3)+(c^48); c=getchar();
	}
	return x*f;
}

const int Inf1=0x3f3f3f3f;
const int Inf2=1e9;
const int mod=1e9+7;
const int N=1e5+5;
int n,m,cnt[N],ans[10];
int rw[N],ln[N],dgn1[N<<1],dgn2[N<<1];
struct Queen{
	int x,y;
	il bool operator<(const Queen &q1)const{
		return x==q1.x?y<q1.y:x<q1.x;
	}
}q[N];

int main(){
	n=read();
	m=read();
	for(rg int i=1;i<=m;++i)
		q[i]=(Queen){read(),read()};
	sort(q+1,q+m+1);
	for(rg int i=1;i<=m;++i){
		int x=q[i].x,y=q[i].y;
		if(rw[x]){
			++cnt[i];
			++cnt[rw[x]];
		}
		if(ln[y]){
			++cnt[i];
			++cnt[ln[y]];
		}
		if(dgn1[x+y]){
			++cnt[i];
			++cnt[dgn1[x+y]];
		}
		if(dgn2[n+x-y]){
			++cnt[i];
			++cnt[dgn2[n+x-y]];
		}
		rw[x]=ln[y]=dgn1[x+y]=dgn2[n+x-y]=i;
	}
	for(rg int i=1;i<=m;++i)
		++ans[cnt[i]];
	for(rg int i=0;i<=8;++i)
		printf("%d ",ans[i]);
	return 0;
}

5、#36.列队
\(n×m\)个数按从大到小顺序填入,填入时,本行已填入的数的个数就是比它大的数的个数。列亦然。所以询问可以做到\(O(1)\)
\(code\):

/********************************
    This code is made by ghy.
    Oj: noi.ac
    Language: C++
    Status: AC
    Complexity: O(nmlogn)
********************************/
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#include <set>
#include <utility>
#include <map>
#include <cstdlib>
#include <ctime>
#define il inline
#define ll long long
#define rg register
#define mp(a,b) make_pair(a,b);
#define pb(a) push_back(a);
#define mst(a,b) memset(a,b,sizeof a) 
using namespace std;
il int read(){
	rg int x=0,f=1; rg char c=getchar();
	while(c<'0' || c>'9'){
		if(c=='-') f=-1; c=getchar();
	}
	while(c>='0' && c<='9'){
		x=(x<<1)+(x<<3)+(c^48); c=getchar();
	}
	return x*f;
}

const int Inf1=0x3f3f3f3f;
const int Inf2=1e9;
const int mod=1e9+7;
const int N=1005;
int n,m,q,ans[N][N];
struct Classmate{
	int x,y,val,id;
	il bool operator<(const Classmate &c)const{
		return val>c.val;
	}
}a[N*N],ord[N];

int main(){
	n=read();
	m=read();
	q=read();
	for(rg int i=1;i<=n*m;++i){
		a[i].id=i;
		a[i].val=read();
	}
	for(rg int i=1;i<=n;++i){
		for(rg int j=1;j<=m;++j)
			ord[j]=a[(i-1)*m+j];
		sort(ord+1,ord+m+1);
		for(rg int j=1;j<=m;++j)
			a[ord[j].id].x=j;
	}
	for(rg int i=1;i<=m;++i){
		for(rg int j=1;j<=n;++j)
			ord[j]=a[(j-1)*m+i];
		sort(ord+1,ord+n+1);
		for(rg int j=1;j<=n;++j)
			a[ord[j].id].y=j;
	}
	for(rg int i=1;i<=n;++i)
		for(rg int j=1;j<=m;++j)
			++ans[a[(i-1)*m+j].x][a[(i-1)*m+j].y];
	while(q--)
		printf("%d\n",ans[read()][read()]);
	return 0;
}

6、#30.\(candy\)
依题意可知,价格一定,为使收益最大,必然要从大往小选,可以记录一下后缀和。
枚举\(A\)店的价值更小还是\(B\)店的价值更小。枚举那家店由最大贡献的商品取到第几个,再二分另一家店在保证最大贡献,且大于那家店的贡献的情况下,由最大贡献的商品取到第几个。最后\(ans\)即为最大值。
\(code\):

/********************************
    This code is made by ghy.
    Oj: noi.ac
    Language: C++
    Status: AC
    Complexity: O(nlogn)
********************************/
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#include <set>
#include <utility>
#include <map>
#include <cstdlib>
#include <ctime>
#define il inline
#define ll long long
#define rg register
#define mp(a,b) make_pair(a,b);
#define pb(a) push_back(a);
#define mst(a,b) memset(a,b,sizeof a) 
using namespace std;
il int read(){
	rg int x=0,f=1; rg char c=getchar();
	while(c<'0' || c>'9'){
		if(c=='-') f=-1; c=getchar();
	}
	while(c>='0' && c<='9'){
		x=(x<<1)+(x<<3)+(c^48); c=getchar();
	}
	return x*f;
}

const int Inf1=0x3f3f3f3f;
const int Inf2=1e9;
const int mod=1e9+7;
const int N=1e5+5;
int n,w,l,mid,r;
int a[N],b[N];
ll suma[N],sumb[N],ans;

int main(){
	n=read();
	w=read();
	for(rg int i=1;i<=n;++i)
		a[i]=read();
	for(rg int i=1;i<=n;++i)
		b[i]=read();
	for(rg int i=1;i<=n;++i){
		suma[i]=suma[i-1]+a[n-i+1];
		sumb[i]=sumb[i-1]+b[n-i+1];
	}
	for(rg int i=1;i<=n;++i){
		l=1;
		r=n;
		while(l<r){
			mid=(l+r)>>1;
			if(suma[i]<=sumb[mid])
				r=mid;
			else
				l=mid+1;
		}
		ans=max(ans,min(suma[i],sumb[l])-w*(i+l));
	}
	for(rg int i=1;i<=n;++i){
		l=1;
		r=n;
		while(l<r){
			mid=(l+r)>>1;
			if(sumb[i]<=suma[mid])
				r=mid;
			else
				l=mid+1;
		}
		ans=max(ans,min(suma[l],sumb[i])-w*(i+l));
	}
	printf("%lld\n",ans);
	return 0;
}

7、#48.\(fac\)
看到n有\(10^{10000}\),就知道有问题。看到要模\(k\),想了一下,发现\(n>=k\)时,结果直接为\(0\)\(n<k\)的情况,直接爆算即可。
唯一要注意的就是读入。读入\(n\)时,发现大于\(8\)位后,可以一直\(getchar()\),但后面的空格也会被读入,所以读入\(k\)时,直接算第一位即可。
\(code\):

/********************************
    This code is made by ghy.
    Oj: noi.cn
    Language: C++
    Status: AC
    Complexity: O(n)
********************************/
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#include <set>
#include <utility>
#include <map>
#include <cstdlib>
#include <ctime>
#define il inline
#define ll long long
#define rg register
#define mp(a,b) make_pair(a,b);
#define pb(a) push_back(a);
#define mst(a,b) memset(a,b,sizeof a)
using namespace std;
bool flg;
il int read(){
	rg int x=0,f=1; rg char c=getchar();
	if(flg)
		while(c>='0' && c<='9')
			c=getchar();
	while(c<'0' || c>'9'){
		if(c=='-') f=-1; c=getchar();
	}
	while(c>='0' && c<='9'){
		x=(x<<1)+(x<<3)+(c^48); c=getchar();
	}
	return x*f;
}
il int readd(){
	rg int x=0,f=1; rg char c=getchar();
	while(c<'0' || c>'9'){
		if(c=='-') f=-1; c=getchar();
	}
	while(c>='0' && c<='9'){
		x=(x<<1)+(x<<3)+(c^48);
		if(x>=1e8){
			flg=1;
			return 1e8;
		}
		c=getchar();
	}
	return x*f;
}

const int Inf1=0x3f3f3f3f;
const int Inf2=1e9;
const int mod=1e9+7;
int a,b,ans=1;

int main(){
	a=readd();
	b=read();
	if(a>=b){
		puts("0");
		return 0;
	}
	while(a>0){
		ans=(1ll*ans*a)%b;
		--a;
	}
	printf("%d\n",ans%b);
	return 0;
}

8、#37.染色
一道dp题。
\(dp[i][j]\)为前\(i\)个格子中填色,其中从后往前最长一段不包含相同颜色格子的后缀长度为\(j\)的方案数。
考虑当前位置,如果不选择最后\(j\)个格子中的颜色,那么最长后缀长度就变成\(j+1\),有\(m-j\)种颜色可供选择。
若选择,那么最长后缀长度就会变成\(1,2,...,j\),各有\(1\)种颜色转移。
所以可以得出方程:\(dp[i][j]=(m-j+1)dp[i-1][j-1]+sigma(k>=j)dp[i-1][k]\)
\(code\):

/********************************
    This code is made by ghy.
    Oj: noi.cn
    Language: C++
    Status: AC
    Complexity: O(nm)
********************************/
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#include <set>
#include <utility>
#include <map>
#include <cstdlib>
#include <ctime>
#define il inline
#define ll long long
#define rg register
#define mp(a,b) make_pair(a,b);
#define pb(a) push_back(a);
#define mst(a,b) memset(a,b,sizeof a) 
using namespace std;
il int read(){
	rg int x=0,f=1; rg char c=getchar();
	while(c<'0' || c>'9'){
		if(c=='-') f=-1; c=getchar();
	}
	while(c>='0' && c<='9'){
		x=(x<<1)+(x<<3)+(c^48); c=getchar();
	}
	return x*f;
}

const int Inf1=0x3f3f3f3f;
const int Inf2=1e9;
const int mod=1e9+7;
const int N=5005;
int n,m,p;
ll ans,dp[N][N],sum[N][N];

int main(){
	n=read();
	m=read();
	p=read();
	dp[0][0]=1;
	for(rg int i=1;i<=n;++i){
		for(rg int j=1;j<=min(i,m-1);++j)
			dp[i][j]=(((dp[i][j]+sum[i-1][j])%p)+((((m-j+1)%p)*dp[i-1][j-1])%p))%p;
		for(rg int j=m-1;j>0;--j)
			sum[i][j]=(sum[i][j+1]+dp[i][j])%p;
	}
	for(rg int i=1;i<m;++i)
		ans=(ans+dp[n][i])%p;
	printf("%d\n",ans);
	return 0;
}

9、#60.\(ball\)
观察到,操作\(2\)限定了球是有序的,操作\(1\)又要插入,所以开一个\(set\)维护每个球的位置。
操作\(1\)直接加入,操作\(2\)可以抽象为每个球都向左移一个,去掉最左的球,在墙前加一个球,具体证明自己画图理解一下即可。
\(set\)中一个一个减固然是爆炸的。所以我们记一个\(cnt\)表示当前减了多少个\(1\)
这样还要注意一点,新插入的球也默认减了\(cnt\),所以得插入比读入数多\(cnt\)的坐标。
\(code\):

/********************************
    This code is made by ghy.
    Oj: noi.ac
    Language: C++
    Status: AC
    Complexity: O(nlogn)
********************************/
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#include <set>
#include <utility>
#include <map>
#include <cstdlib>
#include <ctime>
#define il inline
#define ll long long
#define rg register
#define mp(a,b) make_pair(a,b);
#define pb(a) push_back(a);
#define mst(a,b) memset(a,b,sizeof a) 
using namespace std;
il int read(){
	rg int x=0,f=1; rg char c=getchar();
	while(c<'0' || c>'9'){
		if(c=='-') f=-1; c=getchar();
	}
	while(c>='0' && c<='9'){
		x=(x<<1)+(x<<3)+(c^48); c=getchar();
	}
	return x*f;
}

const int Inf1=0x3f3f3f3f;
const int Inf2=1e9;
const int mod=1e9+7;
int n,q,p,cnt;
set <int> s;

int main(){
	n=read();
	q=read();
	p=read();
	for(rg int i=1;i<=n;++i)
		s.insert(read());
	while(q--){
		if(read()==1)
			s.insert(read()+cnt);
		else{
			s.erase(s.begin());
			s.insert(p+(cnt++));
		}
	}
	while(s.size()){
		printf("%d ",*s.begin()-cnt);
		s.erase(s.begin());
	}
	return 0;
}

10、#64.\(sort\)
假设我们已经知道第\(L\)的数是\(x\),第\(R\)的数是\(y\)
那其实就只需要找到[x+1,y+1]这一段,然后再加上一定数量的x和y就是答案。
于是可以枚举\(a[i]\),二分\(b[j]\)找到。
然后考虑怎么找第\(L\)的数是多少。
其实是二分出一个数,然后比较\(L\)和小于它的个数。
这个小于它的个数怎么算呢,还是二分,细节见代码。
惨痛教训:不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!不要弄混大小写!(本题将\(L\)\(l\)弄混了)
\(code\):

/********************************
    This code is made by ghy.
    Oj: noi.ac
    Language: C++
    Status: AC
    Complexity: O(nlog^2n)
********************************/
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#include <set>
#include <utility>
#include <map>
#include <cstdlib>
#include <ctime>
#define il inline
#define rg register
#define int long long
#define mp(a,b) make_pair(a,b);
#define pb(a) push_back(a);
#define mst(a,b) memset(a,b,sizeof a) 
using namespace std;
il int read(){
	rg int x=0,f=1; rg char c=getchar();
	while(c<'0' || c>'9'){
		if(c=='-') f=-1; c=getchar();
	}
	while(c>='0' && c<='9'){
		x=(x<<1)+(x<<3)+(c^48); c=getchar();
	}
	return x*f;
}

const int N=1e5+5;
int n,l,r;
int a[N],b[N],ans[N];

il int rk(int val){
	int cnt=0;
	for(rg int i=1;i<=n;++i){
		int L=0,R=n,num=0;
		while(L<=R){
			int mid=(L+R)>>1;
			if(a[i]+b[mid]<val){
				L=mid+1;
				num=mid;
			}
			else
				R=mid-1;
		}
		cnt+=num;
	}
	return cnt;
}

signed main(){
	n=read();
	l=read();
	r=read();
	for(rg int i=1;i<=n;++i)
		a[i]=read();
	for(rg int i=1;i<=n;++i)
		b[i]=read();
	sort(a+1,a+n+1);
	sort(b+1,b+n+1);
	int L=a[1]+b[1];
	int R=a[n]+b[n];
	int ansl,ansr;
	while(L<=R){
		int mid=(L+R)>>1;
		if(rk(mid)>=l)
			R=mid-1;
		else{
			L=mid+1;
			ansl=mid;
		}
	}
	L=a[1]+b[1];
	R=a[n]+b[n];
	while(L<=R){
		int mid=(L+R)>>1;
		if(rk(mid)>=r)
			R=mid-1; 
		else{
			L=mid+1;
			ansr=mid;
		}
	}
	int mn,mx,cnt=0;
	for(rg int i=1;i<=n;++i){
		L=1;
		R=n;
		mn=n+1;
		mx=-1;
		while(L<=R){
			int mid=(L+R)>>1;
			if(a[i]+b[mid]>ansl){
				mn=mid;
				R=mid-1;
			}
			else
				L=mid+1;
		}
		L=1;
		R=n;
		while(L<=R){
			int mid=(L+R)>>1;
			if(a[i]+b[mid]<ansr){
				mx=mid;
				L=mid+1;
			}
			else
				R=mid-1;
		}
		for(rg int j=mn;j<=mx;++j)
			ans[++cnt]=a[i]+b[j];
	}
	for(rg int i=l;i<=min(r,rk(ansl+1));++i)
		printf("%lld ",ansl);
	sort(ans+1,ans+cnt+1);
	for(rg int i=1;i<=cnt;++i)
		printf("%lld ",ans[i]);
	for(rg int i=cnt+min(r,rk(ansl+1))+1;i<=r;++i)
		printf("%lld ",ansr);
	return 0;
}

11、#54.\(inform\)
最小生成树板子题。
首先注意一点:第一次空降在哪个点都行,因为最小生成树只有一棵,空降任意点费用也想同。
最小生成树的过程中,如果没有点到树的距离比空降的费用小,就直接空降与树相邻的点即可。
惨痛教训:读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!读题细致!(本题忘了读“平方”)
\(code\):

/********************************
    This code is made by ghy.
    Oj: noi.ac 
    Language: C++
    Status: AC
    Complexity: O(n^2)
********************************/
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#include <set>
#include <utility>
#include <map>
#include <cstdlib>
#include <ctime>
#define il inline
#define ll long long
#define rg register
#define mp(a,b) make_pair(a,b);
#define pb(a) push_back(a);
#define mst(a,b) memset(a,b,sizeof a) 
using namespace std;
il int read(){
	rg int x=0,f=1; rg char c=getchar();
	while(c<'0' || c>'9'){
		if(c=='-') f=-1; c=getchar();
	}
	while(c>='0' && c<='9'){
		x=(x<<1)+(x<<3)+(c^48); c=getchar();
	}
	return x*f;
}

const int Inf1=0x3f3f3f3f;
const int Inf2=1e9;
const int mod=1e9+7;
const int N=5005;
int n,v,mn,id;
int x[N],y[N];
ll dis[N][N],d[N],ans;
bool inque[N]; 

int main(){
	n=read();
	v=read();
	for(rg int i=1;i<=n;++i){
		x[i]=read();
		y[i]=read();
	}
	for(rg int i=1;i<=n;++i)
		for(rg int j=i+1;j<=n;++j)
			dis[i][j]=dis[j][i]=1ll*(x[i]-x[j])*(x[i]-x[j])+1ll*(y[i]-y[j])*(y[i]-y[j]);
	inque[1]=1;
	for(rg int i=2;i<=n;++i)
		d[i]=dis[1][i];
	for(rg int i=1;i<n;++i){
		mn=0x7fffffff;
		for(rg int j=1;j<=n;++j)
			if(!inque[j] && d[j]<mn){
				id=j;
				mn=d[j];
			}
		inque[id]=1;
		ans+=min(d[id],1ll*v);
		for(rg int j=1;j<=n;++j)
			if(!inque[j])
				d[j]=min(d[j],dis[id][j]);
	}
	printf("%lld\n",ans+v);
	return 0;
}
posted @ 2020-02-27 23:24  cjghy  阅读(196)  评论(0)    收藏  举报