首页 > 其他分享 >[USACO22JAN] Minimizing Haybales P 题解

[USACO22JAN] Minimizing Haybales P 题解

时间:2024-11-06 17:57:04浏览次数:2  
标签:USACO22JAN Haybales 题解 入度 入队 Minimizing define

[USACO22JAN] Minimizing Haybales P

随机化?五分。

显然对于任意 \(a_i,a_j\),若 \(|a_i-a_j|>K\),则这两堆草的先后顺序永远不会改变。所以易得暴力:对于所有这样的 \(i,j\),不妨设 \(i<j\),则连一条 \(i\to j\) 的边,答案就是这个图字典序最小的拓扑排序,优先队列即可。

void toposort(){
	priority_queue<pair<int,int>>q;
	for(int i=1;i<=n;++i) if(!in[i]) q.emplace(-h[i],i);
	while(!q.empty()){
		int u=q.top().second;
		q.pop();
		write(h[u]);
		for(int i=head[u];i;i=e[i].to)
			if(--in[e[i].v]==0)
				q.emplace(-h[e[i].v],e[i].v);
	}
}

int main(){
	n=read(),k=read();
	for(int i=1;i<=n;++i) h[i]=read();
	for(int i=1;i<=n;++i)
		for(int j=i+1;j<=n;++j)
			if(abs(h[i]-h[j])>k)
				addedge(i,j),++in[j];
	toposort();
	return fw,0;
}

考虑优化,发现复杂度瓶颈在于连边。正常拓扑排序的操作为:将所有入度为零的点入队,每次删掉当前点。那么神奇地,对于暴力的每一步我们都想办法优化:

  • 如何求初始的入度?将原数组离散化,二分找到所有和当前点相差超过 \(K\) 的点,点数就是入度。然后把这些点加入线段树,就完成了入队的操作。
  • 如何维护全局最小值?线段树啊。
  • 如何删点?还是二分找到所有和当前点相差超过 \(K\) 的节点,将这些点的入度 \(-1\),然后给当前点的入度 \(+\infty\),就完成了删点的操作。
#include<bits/stdc++.h>
#define fw fwrite(obuf,p3-obuf,1,stdout)
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++)
#define putchar(x) (p3-obuf<1<<20?(*p3++=(x)):(fw,p3=obuf,*p3++=(x)))
using namespace std;

char buf[1<<20],obuf[1<<20],*p1=buf,*p2=buf,*p3=obuf,str[20<<2];
int read(){
	int x=0;
	char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return x;
}
template<typename T>
void write(T x,char sf='\n'){
	if(x<0)putchar('-'),x=~x+1;
	int top=0;
	do str[top++]=x%10,x/=10;while(x);
	while(top)putchar(str[--top]+48);
	if(sf^'#')putchar(sf);
}
constexpr int MAXN=1e5+5;
int n,k,h[MAXN],b[MAXN],tot;
int deg[MAXN];
unordered_map<int,bool>vis;
struct{
	#define lp p<<1
	#define rp p<<1|1
	#define mid ((s+t)>>1)
	pair<int,int>st[MAXN<<2];
	int lazy[MAXN<<2];
	void build(int s,int t,int p){
		if(s==t){
			st[p]={deg[s],s};
			return;
		}
		build(s,mid,lp),build(mid+1,t,rp);
		st[p]=min(st[lp],st[rp]);
	}
	void pushdown(int p){
		if(!lazy[p]) return;
		st[lp].first+=lazy[p];
		st[rp].first+=lazy[p];
		lazy[lp]+=lazy[p];
		lazy[rp]+=lazy[p];
		lazy[p]=0;
	}
	void mdf(int l,int r,int k,int s=1,int t=n,int p=1){
		if(l>r) return;
		if(l<=s&&t<=r) return st[p].first+=k,lazy[p]+=k,void();
		pushdown(p);
		if(l<=mid) mdf(l,r,k,s,mid,lp);
		if(mid<r) mdf(l,r,k,mid+1,t,rp);
		st[p]=min(st[lp],st[rp]);
	}
	#undef mid
}T;
struct{
	#define lowbit(x) (x&-x)
	int c[MAXN];
	void add(int x,int k){
		while(x<=n) c[x]+=k,x+=lowbit(x);
	}
	int sum(int x){
		int res=0;
		while(x) res+=c[x],x-=lowbit(x);
		return res;
	}
}B;

int main(){
	n=read(),k=read();
	for(int i=1;i<=n;++i) h[i]=b[i]=read();
	sort(b+1,b+n+1);tot=n;
	for(int i=1;i<=n;++i)
		h[i]=lower_bound(b+1,b+tot+1,h[i])-b+vis[h[i]]++;
	for(int i=1;i<=n;++i){
		int x=lower_bound(b+1,b+tot+1,b[h[i]]-k)-b-1;
		int y=lower_bound(b+1,b+tot+1,b[h[i]]+k+1)-b-1;
		deg[h[i]]=i-1+B.sum(x)-B.sum(y);
		B.add(h[i],1);
	}
	T.build(1,n,1);
	for(int i=1;i<=n;++i){
		int sh=T.st[1].second;
		write(b[sh]);
		int x=lower_bound(b+1,b+tot+1,b[sh]-k)-b-1;
		int y=lower_bound(b+1,b+tot+1,b[sh]+k+1)-b-1;
		T.mdf(1,x,-1);
		T.mdf(y+1,n,-1);
		T.mdf(sh,sh,1e9);
	}
	return fw,0;
}

标签:USACO22JAN,Haybales,题解,入度,入队,Minimizing,define
From: https://www.cnblogs.com/laoshan-plus/p/18530720

相关文章

  • [USACO21DEC] Tickets P 题解
    [USACO21DEC]TicketsP首先我们思考暴力的\(O(n^2)\)怎么做。显然比起每次以\(i\)为起点跑\(n\)遍最短路,建反图后分别以\(1\)和\(n\)为起点跑两遍最短路是更加经济的方式。然后你可能会以为\(\text{dis}(1,i)+\text{dis}(n,i)\)就是答案了,之后你就会发现连样例都过......
  • 【问题解决】java.lang.SecurityException: JCE cannot authenticate the provider BC
    问题复现历史项目升级JDK(由1.7升级到8),进行加密/解密时出现报错java.lang.SecurityException:JCEcannotauthenticatetheproviderBC。问题原因Wikipa上查到JCE的描述如下:JavaCryptographyExtension(JCE)isanofficiallyreleasedStandardExtensiontotheJavaPl......
  • 【问题解决】Tomcat由低于8版本升级到高版本使用Tomcat自带连接池报错无法找到表空间
    问题复现项目上历史项目为解决漏洞扫描从Tomcat6.0升级到了9.0版本,服务启动的日志显示如下警告,数据源是通过JNDI方式在server.xml中配置的,控制台上狂刷无法找到表空间的错误(没截图)报错:06-Nov-202410:32:03.701警告[main]java.util.ArrayList.forEachName=数据源Proper......
  • CF1909题解
    CF1909A一眼秒之题,我们发现就是四个方向选三个方向,若是存在一个点它的方向恰好在(0,0)点的另外一个方向,则一定不成立枚举4个方向,发现有点在这个方向,显然选除这个点之外的三个方向的方案就不可行点击查看代码#include<bits/stdc++.h>usingnamespacestd;constintN=105;int......
  • 题解:P7082 [NWRRC2013] Dwarf Tower
    涉及知识点:动态规划。解题思路设\(dp_i\)为得到\(i\)最小的花费。可以得到转移方程:\(dp_{a_i}=\min(dp_{x_i}+dp_{y_i},dp_{a_i})\)。很明显最多迭代\(n\)次,还需要再外面套一个循化即可。但是有些OJ没有洛谷跑得快,所以需要加一点优化。如果当前循环没有更新......
  • 【题解】CF1956
    CF1956A简要题意有\(n\)个人玩一个游戏,把这\(n\)个人分别编号为\(1\)到\(n\)。每一轮,编号为\(a_1,a_2,\ldots,a_k\)(\(a\)序列递增)的人会被踢出这个游戏,剩下的人会补齐空位并重新从\(1\)开始编号。当某一轮没有人被踢出时,游戏结束,剩下没有被踢出的人成为......
  • “SSL 证书验证失败”问题解决方法“urllib.error.URLError: <urlopen error [SSL: CER
    第一部分:问题描述第二部分:解决方法错误的代码:dataset_train=datasets.MNIST('../data/mnist/',train=True,download=True,transform=trans_mnist)dataset_test=datasets.MNIST('../data/mnist/',train=False,download=True,transform=trans......
  • P6667 [清华集训2016] 如何优雅地求和 题解
    一道非常有启发性的题目。思路考虑对于一个给出点值的多项式函数如何处理。我们发现,对于一个\(m\)次多项式\(f(x)\),由于\(\binom{x}{i}\)为\(i\)次多项式,所以说我们必定可以把一个多项式函数写成如下模样:\[F(k)=\sum_{i=0}^m\binom{k}{i}f_i\]可以看出,\(f_i\)实际上......
  • CSP-J2024题解
    T1扑克牌本题要求:在给定的扑克牌的基础上,还需要多少张牌可以让扑克牌凑成一整套,试题中读入的字符串每个都代表一张合法的扑克牌。可以使用C++STL中的set(集合)完成本题。这是因为,set可以自动去重,去除重复的牌(字符串)后,剩下的字符串就是实际拥有的不同的牌。而一副扑克牌有......
  • ABC378 E 题解
    ABC378E题解题意给定序列\(A\),求\(\sum_{1\lel\ler\len}(\sum_{l\lei\ler}A_i\modM)\)计算所有区间和取模之后的结果再求和。注意外层是没有取模的。如果是外层也要取模的情况,那还是十分好办的,直接贡献法计算每个数字被统计了多少次就可以了。问题就在于外层没......