USACO2018DEC PLATINUM

就按(博主认为的)难度顺序排吧。

Sort It Out

分析

容易发现选出的集合一定是所有逆序对的一个最小覆盖集,那么剩下的就一定是一个LIS。仔细想想还可以发现字典序第\(k\)小的最小覆盖集的补集一定是字典序第\(k\)大的LIS,所以找到这个序列字典序第\(k\)大的LIS就好了。

代码

#include <bits/stdc++.h>

#define rin(i,a,b) for(register int i=(a);i<=(b);++i)
#define irin(i,a,b) for(register int i=(a);i>=(b);--i)
#define trav(i,a) for(register int i=head[a];i;i=e[i].nxt)
typedef long long LL;

using std::cin;
using std::cout;
using std::endl;

inline LL read(){
	LL x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}

const int MAXN=100005;
const LL inf=1e18+1;

int n,a[MAXN],bit[MAXN],f[MAXN];
LL k,retcnt,cnt[MAXN],g[MAXN];
bool vis[MAXN];

struct number{
	int pos,val,f;LL g;
	inline friend bool operator < (number x,number y){
		return x.f==y.f?x.val>y.val:x.f>y.f;
	}
}b[MAXN];

#define lowbit(x) ((x)&(-(x)))

inline void upd(int x,int kk,LL ll){
	for(register int i=x;i<=n;i+=lowbit(i)){
		if(kk<bit[i]) continue;
		else if(kk==bit[i]){
			cnt[i]=std::min(cnt[i]+ll,inf);
		}
		else{
			bit[i]=kk;
			cnt[i]=ll;
		}
	}
}

inline int ask(int x){
	int ret=0;retcnt=1;
	for(register int i=x;i;i-=lowbit(i)){
		if(bit[i]<ret) continue;
		else if(bit[i]==ret){
			retcnt=std::min(retcnt+cnt[i],inf);
		}
		else{
			ret=bit[i];
			retcnt=cnt[i];
		}
	}
	return ret;
}

#undef lowbit(x)

int main(){
	n=read(),k=read();int ans=0;
	rin(i,1,n) a[i]=read();
	irin(i,n,1){
		f[i]=ask(n-a[i]+1)+1;
		g[i]=retcnt;
		upd(n-a[i]+1,f[i],g[i]);
		b[i]=(number){i,a[i],f[i],g[i]};
		ans=std::max(ans,f[i]);
	}
	ans=n-ans;
	std::sort(b+1,b+n+1);
	int now=b[1].f,pos=0,las=0;LL temp=0;
	rin(i,1,n){
		if(b[i].f!=now||b[i].pos<pos||b[i].val<las) continue;
		if(temp+b[i].g>=k){
			k-=temp;
			temp=0;
			--now;
			pos=b[i].pos;
			las=b[i].val;
			vis[b[i].val]=true;
		}
		else{
			temp+=b[i].g;
		}
	}
	printf("%d\n",ans);
	rin(i,1,n) if(!vis[i]) printf("%d\n",i);
	return 0;
}

The Cow Gathering

分析

有一个简单的结论,就是如果\(a\)必须比\(b\)先离开聚会,那么以\(b\)为根\(a\)的子树内的点的答案就一定是\(0\)

但是明显这样还会有些问题。显然目前所有答案还有可能为\(1\)的点是连通的,因此一些树边的方向可以被确定。如果我们在已经确定了的关系中找到了环,那么说明整张图的所有点的答案就都是\(0\)

尽管想到了正解但还是各种疑惑,可能之后会在这里补充一点东西。

代码

#include <bits/stdc++.h>

#define rin(i,a,b) for(register int i=(a);i<=(b);++i)
#define irin(i,a,b) for(register int i=(a);i>=(b);--i)
#define trav(i,a) for(register int i=head[a];i;i=e[i].nxt)
typedef long long LL;

using std::cin;
using std::cout;
using std::endl;

inline LL read(){
	LL x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}

const int MAXN=100005;

int n,m,ecnt,head[MAXN];
int top,sta[MAXN],pos[MAXN],tag[MAXN];
int tot,uu[MAXN<<1],vv[MAXN<<1],deg[MAXN<<1];
bool ok[MAXN];
std::vector<int> vec[MAXN];

struct Edge{
	int to,nxt;
}e[MAXN<<1];

inline void add_edge(int bg,int ed){
	++ecnt;
	e[ecnt].to=ed;
	e[ecnt].nxt=head[bg];
	head[bg]=ecnt;
}

void dfs1(int x,int pre){
	sta[++top]=x;
	pos[x]=top;
	rin(i,0,(int)vec[x].size()-1){
		int ver=vec[x][i];
		if(!pos[ver]) ++tag[ver];
		else{
			++tag[1];
			--tag[sta[pos[ver]+1]];
		}
	}
	trav(i,x){
		int ver=e[i].to;
		if(ver==pre) continue;
		dfs1(ver,x);
	}
	--top;
	pos[x]=0;
}

void dfs2(int x,int pre,int now){
	now+=tag[x];
	if(!now) ok[x]=true;
	trav(i,x){
		int ver=e[i].to;
		if(ver==pre) continue;
		dfs2(ver,x,now);
	}
}

void dfs3(int x,int pre){
	if(pre) ++tot,uu[tot]=pre,vv[tot]=x;
	trav(i,x){
		int ver=e[i].to;
		if(ver==pre) continue;
		dfs3(ver,x);
	}
}

std::queue<int> q;

void topo(){
	while(!q.empty()) q.pop();
	rin(i,1,n) if(!deg[i]) q.push(i);
	int cnt=0;
	while(!q.empty()){
		int x=q.front();q.pop();
		++cnt;
		trav(i,x){
			int ver=e[i].to;
			--deg[ver];
			if(!deg[ver]) q.push(ver);
		}
	}
	if(cnt<n){
		rin(i,1,n) printf("0\n");
		exit(0);
	}
}

int main(){
	n=read(),m=read();
	rin(i,2,n){
		int u=read(),v=read();
		add_edge(u,v);
		add_edge(v,u);
	}
	rin(i,1,m){
		int u=read(),v=read();
		vec[v].push_back(u);
		++tot,uu[tot]=v,vv[tot]=u;
	}
	dfs1(1,0);
	dfs2(1,0,0);
	int root=0;
	rin(i,1,n){
		if(ok[i]){
			root=i;
			break;
		}
	}
	if(!root){
		rin(i,1,n) printf("0\n");
		return 0;
	}
	dfs3(root,0);
	ecnt=0,memset(head,0,sizeof head);
	rin(i,1,tot){
		add_edge(uu[i],vv[i]);
		++deg[vv[i]];
	}
	topo();
	rin(i,1,n) printf("%d\n",ok[i]?1:0);
	return 0;
}

Balance Beam

分析

把期望和凸包结合在了一块,这道题有点神啊。。

贴一个认为讲的不错的博客,本人就不在这里献丑了。

戳我感受大神的洗礼

代码

#include <bits/stdc++.h>

#define rin(i,a,b) for(register int i=(a);i<=(b);++i)
#define irin(i,a,b) for(register int i=(a);i>=(b);--i)
#define trav(i,a) for(register int i=head[a];i;i=e[i].nxt)
typedef long long LL;

using std::cin;
using std::cout;
using std::endl;

inline int read(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}

const int MAXN=100005;

int n,f[MAXN],sta[MAXN],top;
LL ans[MAXN];

bool isleft(int x1,int y1,int x2,int y2,int x3,int y3){
	int X1=x2-x1,Y1=y2-y1,X2=x3-x2,Y2=y3-y2;
	return 1ll*X1*Y2-1ll*X2*Y1>=0;
}

int main(){
	n=read();
	rin(i,1,n) f[i]=read();
	top=0;sta[++top]=0;
	rin(i,1,n+1){
		while(top>1&&isleft(sta[top-1],f[sta[top-1]],sta[top],f[sta[top]],i,f[i])) --top;
		sta[++top]=i;
	}
	rin(i,2,top){
		rin(j,sta[i-1]+1,sta[i])
			ans[j]=(1ll*f[sta[i]]*(j-sta[i-1])+1ll*f[sta[i-1]]*(sta[i]-j))*100000/(sta[i]-sta[i-1]);
	}
	rin(i,1,n) printf("%lld\n",ans[i]);
	return 0;
}

posted on 2019-03-07 20:37  ErkkiErkko  阅读(247)  评论(2编辑  收藏  举报