Codeforces Round #569 (Div. 1)

Codeforces Round #569 (Div. 1)

A Valeriy and Deque

考虑先走n-1步,那么走完了n-1步后最大的数一定就在最前面了,接下来的操作会让后面的n-1个数进入循环,那么对于一个询问(m_i),如果(m_i<n-1),那么直接回答即可,否则将(m_i)对n-1取模,然后回答。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cctype>
#define qmin(x,y) (x=min(x,y))
#define qmax(x,y) (x=max(x,y))
#define vic vector<int>
#define vit vic::iterator
#define pir pair<int,int>
#define fr first
#define sc second
#define mp(x,y) make_pair(x,y)
#define rsort(x,y) sort(x,y),reverse(x,y)
using namespace std;

inline char gc() {
//	static char buf[100000],*p1,*p2;
//	return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
	return getchar();
}

template<class T>
int read(T &ans) {
	ans=0;char ch=gc();T f=1;
	while(!isdigit(ch)) {
		if(ch==EOF) return -1;
		if(ch=='-') f=-1;
		ch=gc();
	}
	while(isdigit(ch))
		ans=ans*10+ch-'0',ch=gc();
	ans*=f;return 1;
}

template<class T1,class T2>
int read(T1 &a,T2 &b) {
	return read(a)!=EOF&&read(b)!=EOF?2:EOF;
}

template<class T1,class T2,class T3>
int read(T1 &a,T2 &b,T3 &c) {
	return read(a,b)!=EOF&&read(c)!=EOF?3:EOF;
}

typedef long long ll;
const int Maxn=1100000;
const int inf=0x3f3f3f3f;

int n,t,a[Maxn],c[Maxn];
ll x;
pir b[Maxn];

signed main() {
//	freopen("test.in","r",stdin);
//	freopen("out","w",stdout);
	read(n,t);
	for(int i=1;i<=n;i++) read(a[i]);
	deque<int> q;
	for(int i=1;i<=n;i++) q.push_back(a[i]);
	for(int i=1;i<n;i++) {
		int x=q.front(); q.pop_front();
		int y=q.front(); q.pop_front();
		b[i]=mp(x,y);
		if(x<y) swap(x,y);
		q.push_front(x);
		q.push_back(y);
	}
	int mx=q.front(); q.pop_front();
	for(int i=1;i<n;i++) c[i]=q.front(),q.pop_front();
	while(t--) {
		read(x);
		if(x<n) printf("%d %d
",b[x].fr,b[x].sc);
		else {
			x-=n;
			printf("%d %d
",mx,c[x%(n-1)+1]);
		}
	}
	return 0;
}

B Tolik and His Uncle

构造题。

((1,1) ightarrow(n,m) ightarrow(1,2) ightarrow(n,m-1) ightarrowcdots ightarrow(n,1) ightarrow(2,1) ightarrow(n-1,m) ightarrowcdots)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cctype>
#define qmin(x,y) (x=min(x,y))
#define qmax(x,y) (x=max(x,y))
#define vic vector<int>
#define vit vic::iterator
#define pir pair<int,int>
#define fr first
#define sc second
#define mp(x,y) make_pair(x,y)
#define rsort(x,y) sort(x,y),reverse(x,y)
using namespace std;

inline char gc() {
//	static char buf[100000],*p1,*p2;
//	return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
	return getchar();
}

template<class T>
int read(T &ans) {
	ans=0;char ch=gc();T f=1;
	while(!isdigit(ch)) {
		if(ch==EOF) return -1;
		if(ch=='-') f=-1;
		ch=gc();
	}
	while(isdigit(ch))
		ans=ans*10+ch-'0',ch=gc();
	ans*=f;return 1;
}

template<class T1,class T2>
int read(T1 &a,T2 &b) {
	return read(a)!=EOF&&read(b)!=EOF?2:EOF;
}

template<class T1,class T2,class T3>
int read(T1 &a,T2 &b,T3 &c) {
	return read(a,b)!=EOF&&read(c)!=EOF?3:EOF;
}

typedef long long ll;
//const int Maxn=;
const int inf=0x3f3f3f3f;

int n,m;

void work1(int x,int y) {
	for(int l=1,r=m;l<=m;l++,r--) printf("%d %d
%d %d
",x,l,y,r);
}

void work2(int x) {
	for(int l=1,r=m;l<=r;l++,r--) {
		if(l!=r) printf("%d %d
%d %d
",x,l,x,r);
		else printf("%d %d
",x,l);
	}
}

signed main() {
//	freopen("test.in","r",stdin);
	read(n,m);
	for(int l=1,r=n;l<=r;l++,r--) {
		if(l!=r) work1(l,r);
		else work2(l);
	}
	return 0;
}

C Serge and Dining Room

考虑要求的实际上就是最大的x,满足价格大于x的菜的数目大于钱数大于x的人数。

那么这个问题就是单点修改,然后查询后缀和,这样很不好搞,于是变成前缀修改,单点查询,然后就可以在线段树上二分了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cctype>
#define qmin(x,y) (x=min(x,y))
#define qmax(x,y) (x=max(x,y))
#define vic vector<int>
#define vit vic::iterator
#define pir pair<int,int>
#define fr first
#define sc second
#define mp(x,y) make_pair(x,y)
#define rsort(x,y) sort(x,y),reverse(x,y)
using namespace std;

inline char gc() {
//	static char buf[100000],*p1,*p2;
//	return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
	return getchar();
}

template<class T>
int read(T &ans) {
	ans=0;char ch=gc();T f=1;
	while(!isdigit(ch)) {
		if(ch==EOF) return -1;
		if(ch=='-') f=-1;
		ch=gc();
	}
	while(isdigit(ch))
		ans=ans*10+ch-'0',ch=gc();
	ans*=f;return 1;
}

template<class T1,class T2>
int read(T1 &a,T2 &b) {
	return read(a)!=EOF&&read(b)!=EOF?2:EOF;
}

template<class T1,class T2,class T3>
int read(T1 &a,T2 &b,T3 &c) {
	return read(a,b)!=EOF&&read(c)!=EOF?3:EOF;
}

typedef long long ll;
const int Maxn=1100000;
const int inf=0x3f3f3f3f;

int tl[Maxn<<2],tr[Maxn<<2],tn[Maxn<<2],bj[Maxn<<2];
int n,m,a[Maxn],b[Maxn],q,opt,x,y;

#define lch (root<<1)
#define rch (root<<1|1)

void build(int root,int l,int r) {
	tl[root]=l,tr[root]=r;
	if(l==r) return ;
	int mid=l+r>>1;
	build(lch,l,mid);
	build(rch,mid+1,r);
}

inline void update(int root) {
	tn[root]=max(tn[lch],tn[rch]);
}

inline void abj(int root,int x) {
	tn[root]+=x;
	bj[root]+=x;
}

void pushdown(int root) {
	if(bj[root]) {
		abj(lch,bj[root]);
		abj(rch,bj[root]);
		bj[root]=0;
	}
}

void chang(int root,int x,int y) {
	int l=tl[root],r=tr[root],mid=l+r>>1;
	if(l==r) {
		tn[root]+=y;
		return ;
	}
	pushdown(root);
	if(x<=mid) {
		chang(lch,x,y);
		update(root);
		return ;
	}
	abj(lch,y);
	chang(rch,x,y);
	update(root);
}

int work(int root) {
	if(tl[root]==tr[root]) return tl[root];
	pushdown(root);
	return work(tn[rch]>=1?rch:lch);
}

signed main() {
//	freopen("test.in","r",stdin);
	read(n,m);
	build(1,1,1000000);
	for(int i=1;i<=n;i++) {
		read(a[i]);
		chang(1,a[i],1);
	}
	for(int i=1;i<=m;i++) {
		read(b[i]);
		chang(1,b[i],-1);
	}
	read(q);
	for(int i=1;i<=q;i++) {
		read(opt,x,y);
		if(opt==1) {
			chang(1,a[x],-1);
			a[x]=y;
			chang(1,a[x],1);
		}
		else {
			chang(1,b[x],1);
			b[x]=y;
			chang(1,b[x],-1);
		}
		if(tn[1]>=1) printf("%d
",work(1));
		else puts("-1");
	}
	return 0;
}

D Fedor Runs for President

考虑加上一条边会增加多少条简单路径,那么把这条边连接的两个点之间的链拎出来,树的形态就变成了一条链上每个点上挂着一颗树,那么答案就等于(n^2-sum_isize[i]^2)。显然选的两个点一定是两个叶子,因为如果不是两个叶子,那么再继续往下走一定会更优。

考虑枚举选的两个点的lca,设(i)为当前枚举的lca的一个儿子,(f_i)(i)这个子树中叶子到(i)的链上的点除了链上的子树外的点的数目的平方的和的最小值。转移为(f_{root}=min_i {f_i+(size[root]-size[i])^2})

现在来考虑统计答案,那么对于当前点的两个儿子(i,j),其答案除了(f_i+f_j)外还有当前点的大小之和,即(f_i+f_j+(n-size[i]-size[j])^2),展开一下有(n^2+(f_i+size[i]^2-2cdot ncdot size[i])+(f_j+size[j]^2-2cdot ncdot size[j])+2cdot size[i]cdot size[j]),那么按照(size)排序后用单调栈处理即可。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cctype>
#define qmin(x,y) (x=min(x,y))
#define qmax(x,y) (x=max(x,y))
#define vic vector<int>
#define vit vic::iterator
#define pir pair<int,int>
#define fr first
#define sc second
#define mp(x,y) make_pair(x,y)
#define rsort(x,y) sort(x,y),reverse(x,y)
using namespace std;

inline char gc() {
//	static char buf[100000],*p1,*p2;
//	return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
	return getchar();
}

template<class T>
int read(T &ans) {
	ans=0;char ch=gc();T f=1;
	while(!isdigit(ch)) {
		if(ch==EOF) return -1;
		if(ch=='-') f=-1;
		ch=gc();
	}
	while(isdigit(ch))
		ans=ans*10+ch-'0',ch=gc();
	ans*=f;return 1;
}

template<class T1,class T2>
int read(T1 &a,T2 &b) {
	return read(a)!=EOF&&read(b)!=EOF?2:EOF;
}

template<class T1,class T2,class T3>
int read(T1 &a,T2 &b,T3 &c) {
	return read(a,b)!=EOF&&read(c)!=EOF?3:EOF;
}

typedef long long ll;
const int Maxn=1100000;
const int inf=0x3f3f3f3f;

int to[Maxn],nxt[Maxn],first[Maxn],tot=1;
int n,m,u,v,d[Maxn],siz[Maxn];
ll f[Maxn],res;
pair<ll,ll> q[Maxn],a[Maxn];

inline void add(int u,int v) {
	to[tot]=v;
	nxt[tot]=first[u];
	first[u]=tot++;
	to[tot]=u;
	nxt[tot]=first[v];
	first[v]=tot++;
}

inline ll sqr(ll x) {
	return x*x;
}

ll cal(pair<ll,ll> x,ll y) {
	return y*x.fr+x.sc;
}

void work(int root,int fa) {
	siz[root]=1,f[root]=1ll*n*n;
	for(int i=first[root];i;i=nxt[i])
		if(to[i]!=fa) work(to[i],root),siz[root]+=siz[to[i]];
	for(int i=first[root];i;i=nxt[i]) if(to[i]!=fa) qmin(f[root],f[to[i]]+sqr(siz[root]-siz[to[i]]));
	int tot=0;
	for(int i=first[root];i;i=nxt[i]) if(to[i]!=fa) a[++tot]=mp(siz[to[i]],to[i]);
	if(!tot) {
		f[root]=1;
		return ;
	}
	sort(a+1,a+tot+1);
	int top=0; q[++top]=mp(2ll*siz[a[1].sc],f[a[1].sc]+sqr(siz[a[1].sc])-2ll*n*siz[a[1].sc]);
	for(int i=2;i<=tot;i++) {
		while(top&&cal(q[top-1],a[i].fr)<cal(q[top],a[i].fr)) top--;
		qmin(res,cal(q[top],a[i].fr)+f[a[i].sc]+sqr(siz[a[i].sc])-2ll*n*siz[a[i].sc]+1ll*n*n);
		pair<ll,ll> temp=mp(2ll*siz[a[i].sc],f[a[i].sc]+sqr(siz[a[i].sc])-2ll*n*siz[a[i].sc]);
		q[++top]=temp;
	}
}

signed main() {
//	freopen("test.in","r",stdin);
	read(n);
	if(n==2) {
		puts("2");
		return 0;
	}
	for(int i=1;i<n;i++) {
		read(u,v);
		d[u]++,d[v]++;
		add(u,v);
	}
	int rt;
	for(int i=1;i<=n;i++) if(d[i]>1) {
		rt=i;
		break;
	}
	res=1ll*n*n;
	work(rt,rt);
	ll ans=1ll*n*(n-1);
	ans+=1ll*n*n-res;
	printf("%I64d
",ans/2);
	return 0;
}

E Alesya and Discrete Math

看到了题目,满脸的不可做,(于是我们看一下题解。所以我就把题解翻译一下就好了。

考虑朴素做法,不失一般性,我们设n为偶数,那么显然我们可以用二分找到使得(f_i(x_i)=frac{L}{2})(x_i),那么按照(x_i)从大到小排序并重新编号,可以发现这个一定是对的。同时这个问题也被分成了两个规模为(frac{n}{2})的子问题,那么复杂度(T(n)=2T(frac{n}{2})+O(nlog w) , T(n)=O(nlog nlog w)),这个是过不了的,所以考虑优化这个过程。

我们要把它分成两个子问题,所以可以随机一个选一个函数(f_i),二分出上面的(x_i),那么把(f_j(x_i)>frac{L}{2})的函数放在左边,反之放在右边,如果等于的话就先单独记出来,能填到左边就填到左边,直到左边放到(frac{n}{2})个数,然后剩下的丢到右边。这时如果左边恰有(frac{n}{2})个数,那么完成,否则如果少于,就向右边找,否则向左边找。这个复杂度是(O(nlog n+nlog w))

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cctype>
#define qmin(x,y) (x=min(x,y))
#define qmax(x,y) (x=max(x,y))
#define vic vector<int>
#define vit vic::iterator
#define pir pair<int,int>
#define fr first
#define sc second
#define mp(x,y) make_pair(x,y)
#define rsort(x,y) sort(x,y),reverse(x,y)
using namespace std;

inline char gc() {
//	static char buf[100000],*p1,*p2;
//	return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
	return getchar();
}

template<class T>
int read(T &ans) {
	ans=0;char ch=gc();T f=1;
	while(!isdigit(ch)) {
		if(ch==EOF) return -1;
		if(ch=='-') f=-1;
		ch=gc();
	}
	while(isdigit(ch))
		ans=ans*10+ch-'0',ch=gc();
	ans*=f;return 1;
}

template<class T1,class T2>
int read(T1 &a,T2 &b) {
	return read(a)!=EOF&&read(b)!=EOF?2:EOF;
}

template<class T1,class T2,class T3>
int read(T1 &a,T2 &b,T3 &c) {
	return read(a,b)!=EOF&&read(c)!=EOF?3:EOF;
}

typedef long long ll;
const int Maxn=1100;
const int inf=0x3f3f3f3f;

int a[Maxn],b[Maxn],c[Maxn],tims;
ll n,L,v;
pair<ll,ll> ans[Maxn];

ll query(ll a,ll b) {
	printf("? %I64d %I64d
",a,b);
	fflush(stdout); ll ans;
	read(ans);
//	ans=b;
//	tims++;
	return ans;
}

ll find(int x,ll k,ll l,ll r) {
	ll mid=l+r>>1;
	while(1) {
		ll y=query(x,mid);
		if(y==k) return mid;
		if(y<k) l=mid+1;
		else r=mid-1;
		mid=l+r>>1;
	}
}

void kth(int l,int r,int k,ll ql,ll qr) {
	if(l==r) return ;
	int x=rand()%(r-l+1)+l;
	ll y=find(a[x],(L/n)*k,ql,qr);
	int mid=k-l+1;
	int l1=l-1,l2=r+1,l3=0;
	c[++l3]=a[x];
	for(int i=l;i<=r;i++) {
		if(i==x) continue;
		ll sxz=query(a[i],y);
		if(sxz<(L/n)*k) b[--l2]=a[i];
		if(sxz==(L/n)*k) c[++l3]=a[i];
		if(sxz>(L/n)*k) b[++l1]=a[i];
	}
	while(l1<k&&l3) b[++l1]=c[l3--];
	if(l1==k) {
		v=y;
		while(l3) b[--l2]=c[l3--];
		for(int i=l;i<=r;i++) a[i]=b[i];
		return ;
	}
	if(l1<k) {
		for(int i=l;i<=r;i++) a[i]=b[i];
		kth(l1+1,r,k,ql,qr);
		return ;
	}
	while(l3) b[--l2]=c[l3--];
	for(int i=l;i<=r;i++) a[i]=b[i];
	kth(l,l1,k,ql,qr);
}

void solve(int l,int r,ll ql,ll qr) {
	if(l==r) {
		ans[a[l]]=mp(ql,qr);
		return ;
	}
	int mid=l+r>>1;
	kth(l,r,mid,ql,qr);
	ll x=v;
	solve(l,mid,ql,x);
	solve(mid+1,r,x,qr);
}

signed main() {
//	freopen("test.in","r",stdin);
//	freopen("out","w",stdout);
	read(n,L);
	for(int i=1;i<=n;i++) a[i]=i;
	solve(1,n,0,1000000000000000000ll);
	puts("!");
	for(int i=1;i<=n;i++) printf("%I64d %I64d
",ans[i].fr,ans[i].sc);
	fflush(stdout);
//	printf("%d
",tims);
	return 0;
}
原文地址:https://www.cnblogs.com/shanxieng/p/11077328.html