5月25日

5月25日

CF1430F Realistic Gameplay

山风好评,真凉快。合唱队的衣服好评,zyn小西装真好看。贪心题。

首先对于某一波怪物,要不换一次弹,打满 \([l,r]\),要么不换弹随便打 \((r-l) \times k<a[i]\) ,要么介于两个中间

先想的是dp[i]表示当前还剩i颗子弹,然后每次要不连着打要不新浪费一次弹。

后来想到不用那么多状态,只要记dp[i]表示最后一次浪费在哪个前面,应该也能过了,详见 Thaumaturge

然后想到可以贪心,如果下面连着的一段怪物不需要换弹,那么一定不换更优(因为要换了后面还有空隙可以换),所以就可以先算出某一段开头处(不一定是一个),所需最小起始子弹就可以不换弹,这个从后往前推一下就好了,尽量放在后面打,因为如果 \(r_{i-1}==l_i\) 的地方可以留给上一段用,每次不仅考虑自己,还要考虑 \(r_i\) 处要留多少给下一波。然后从前往后贪一遍什么时候换弹,一定换才换。

#include <bits/stdc++.h>
typedef long long ll;
const int N=2005;
int n,k,l[N],r[N],a[N];
ll ans,dp[N];
int main(){
	scanf("%d%d",&n,&k);
	for (int i=1;i<=n;i++)
		scanf("%d%d%d",&l[i],&r[i],&a[i]),ans+=a[i];
	for (int i=n;i>=1;i--){
		dp[i]=(r[i]==l[i+1]?dp[i+1]:0);
		if ((ll)(r[i]-l[i]+1)*k<a[i]+dp[i])
			return puts("-1"),0;
		dp[i]=dp[i]+a[i]-(ll)(r[i]-l[i])*k;
		if (dp[i]<0) dp[i]=0;
	}
	ll res=0;
	for (int i=1;i<=n;i++){
		if (res<dp[i]){
			ans+=res;
			res=k;
		}
		res=(res-a[i])%k;
		res=(res+k)%k;
	}
	printf("%lld\n",ans);
} 

CF1425I Impressive Harvesting of The Orchard

根号分治+吉老师线段树

有点困,看了一眼题解是根号分治以为按子树大小分治,想了半天想不出发现是按 \(a_i\) 分治。

对于大于根号的,直接dfs记录父亲节点被采集的时间点,每次 \(+a_i\) 二分到下一次被采集,算答案。

对于小于根号的,枚举一下不同的 \(a_i\) ,分别建一棵线段树。对于每一次询问,只对 \(\le T\) 的有关系,答案即为 \(\le T\) 的个数和深度和,然后再讲所有 \(\le T\) 的数赋值为 \(T+a_i\)。听说这个东西可以用吉老师线段树做,这个东西可以参考吉老师的课件

突然去看了一眼记录,看起来写nq比较靠谱,不想写了怎么办啊。算了算了还是先不写了

SOJ1281 简

相同长度的链一样,链长共6中,记搜+容斥

soj1282 单

3*n网格图最短路求和,分治+dp+二维数点

CF1251D Nastia Plays with a Tree

又到了 水题量的夜晚时刻了!

首先肯定找一个度数为1的点当链顶,然后,度数>2的是肯定要断掉某些边的,感觉是只要优先断两边度数都>2的,然后挑一个子树的叶子节点连到某一个叶子就好了,不知道对不对,我去看题解了。

感觉题解不太符合我的想法(什么鬼话)?还是自己写一发好了,发现连边不用再删边时处理,最后随便首尾相连就好了

冲题量失败了,有点问题,完善一下,像树形dp一样先把下面做完,如果有两条链就并起来,断掉x和fa的边,而那些多于两条边的也要断掉。

#include <bits/stdc++.h>
const int N=200005;
int n,d[N],last[N],Next[N<<1],to[N<<1],edge,f[N],use[N],ans;
int son1[N],son2[N];
int T,x,y;
struct Edge{
	int x,y;
}a[N]; 
void clear(){
	for (int i=1;i<=n;i++) d[i]=0,last[i]=0,son1[i]=son2[i]=0;
	edge=0;
}
void add(int x,int y){
	to[++edge]=y;
	Next[edge]=last[x];
	last[x]=edge;
}
void dfs(int x,int y){//x/y表示和父亲有没有边 
	f[x]=y;
	int tg1=0,tg2=0;
	for (int i=last[x];i;i=Next[i]){
		int u=to[i];
		if (u==y) continue;
		dfs(u,x);
		if (!use[u]) continue;
		if (!tg1) tg1=u;
		else if (!tg2) tg2=u;
		else{
			use[u]=0,ans++;
			son2[u]=u;
		}
	}
	if (tg1 && tg2){
		son1[x]=son1[tg1];
		son2[x]=son1[tg2];
		use[x]=0;
		if (x!=1) ans++;
	}else if (tg1) son1[x]=son1[tg1],use[x]=1;
	else son1[x]=x,use[x]=1;
}
int main(){
	scanf("%d",&T);
	while (T--){
		clear();
		scanf("%d",&n);
		for (int i=1;i<n;i++){
			scanf("%d%d",&x,&y);
			add(x,y),add(y,x);
			d[x]++,d[y]++; 
		} 
		ans=0;
		dfs(1,0);
		printf("%d\n",ans);
		int lst=son1[1];
		for (int i=2;i<=n;i++)
			if (!use[i]){
				printf("%d %d %d %d\n",i,f[i],lst,son1[i]);
				if (!son2[i]) lst=i;
				else lst=son2[i];
			}
		lst=son1[1];
	
	}
}
posted @ 2021-05-26 10:10  flyfeather  阅读(76)  评论(0编辑  收藏  举报