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];
}
}