2026年3月解题报告

[USACO20OPEN] Haircut G

假设 FJ 每秒长 \(1mm\) 的头发。
发现第 \(i\) 根头发要到第 \(a_i\) 秒才对答案产生影响,并且对答案的贡献即为满足 \(a_i<a_j(j<i)\)\(j\) ,就是逆序对。
利用树状数组维护即可。

CF1679C Rooks Defenders

维护两个树状数组,分别对应行和列。
查询时只需要查询子矩形对应的行区间和列区间有多少行或列被覆盖即可。
只要行和列中至少有一个被完全覆盖,那么就是满足要求的,反之一定不满足。

   fx=1;fy=1;
   int sx=query(x_2,tr1)-query(x_1-1,tr1);
   if(sx<x_2-x_1+1)fx=0;
   int sy=query(y_2,tr2)-query(y_1-1,tr2);
   if(sy<y_2-y_1+1)fy=0;

而添加车的操作不能想当然,要对当前的棋盘局势进行判断:

if(opt==1){
   if(!cntx[x_1])add(x_1,1,tr1);
   if(!cnty[y_1])add(y_1,1,tr2);
   cntx[x_1]++;cnty[y_1]++;
}

减少同理。

[BJOI2016] 回转寿司

CDQ分治。
为了写这一题学了学,不能说掌握了qwq。。。

void cdq(int l,int r){
    if(l==r)return;
    int mid=(l+r)/2;
    cdq(l,mid);
    cdq(mid+1,r);
    int head=l,tail=l-1;
    for(int i=mid+1;i<=r;i++){
        while(tail+1<=mid&&s[i]>=s[tail+1]+L)tail++;
        while(head<=mid&&s[i]>s[head]+R)head++;
        ans+=tail-head+1;
    }
    sort(s+l,s+r+1);
}

守墓人

把主要墓碑和其余墓碑一起看(别歧视次要墓碑),依旧分块板子,依旧没脑子。。。

I Hate It

分块。
维护区间最值,接着实现区间修改即可。

鬼子进村

\(sum_i\) 表示 \(i\) 块中被摧毁的数量,\(flag_i\) 表示 \(i\) 是否被摧毁。
对于上一个摧毁的房子,用栈维护。

现在考虑查询:

如果 \(x\) 号房子已经被摧毁,输出 \(0\),否则,需要找到 \(x\) 号房子左边/右边第一个被摧毁的房子,设为 \(l,r\) ,答案为 \(r−l−1\)

现在考虑怎么找到左边第一个被摧毁的房子,右边同理

先从后往前找 \(x\) 左边第一个包含 \(x\) 的块(这个块不一定是整块)被摧毁的房子,如果没有,则继续往左,一个一个块找。如果这个块 \(sum_i>0\) ,则返回 \(0\)

数列找不同

本题使用莫队。

\([l,r]\) 这个区间里有几个不同的数,再和区间长度作比较。

大坑点:要注意 q[] 数组 sort 后会彻底乱序,于是还要在基础莫队的基础上加上一个 Query_len[] 数组,记录区间长度。
(卡了我 \(20min\))

...
int query_len[MAXN];
...
block_size=max(1,(int)(n/sqrt(m)));
for(int i=0;i<m;i++){
   ...
   query_len[i]=q[i].r-q[i].l+1;
}
...
for(int i=0;i<m;i++){
   if(ans[i]==query_len[i])
     ...
}

998. 起床困难综合症

位运算 好题。

由于位运算在二进制表示下不进位,于是 \(ans\) 的第 \(k\) 位只和选择的数字的第 \(k\) 位有关。

我们从高位往低位遍历,考虑第 \(bit\) 位:
1.高一位的数值 \(+(1<<bit) <=m\) ;2.这一关放零的伤害 \(<\) 放一的。满足这两点的放一;否则放二。

96. 奇怪的汉诺塔

本题的汉诺塔确实很神奇。。。有四根柱子。

于是我们首先拍上来一个普通版的递推:

 for(int i=1;i<=12;i++)d[i]=(1<<i)-1;

接着,我们以三根柱子的为跳板,徒手推四根的:
先把 \(i\) 根放到\(B\),即 \(f_i\) ;再将在 \(A\)\(n-i\) 根放到 \(D\) ,即 \(d_i\) ;再将 \(B\)\(i\) 根放到 \(D\) ,又是 \(f_i\)
最后取最小即可。

 f[0]=0;
     for(int i=1;i<=12;i++)
         for(int j=0;j<i;j++)
             f[i]=min(f[i],2*f[j]+d[i-j]);

98. 分形之城

DFS 好题。

calc(n,m) ,可以先递归求 calc(n-1,m%cnt) ,其中,\(cnt=4^{n-1}\) 即第 N 级时的房子总个数。
在递归时分类讨论四种情况:

  • 左上象限
  • 右上象限
  • 右下象限
  • 左下象限
 if(z==0)return make_pair(-y-len,-x+len);
 if(z==1)return make_pair(x+len,y+len);
 if(z==2)return make_pair(x+len,y-len);
 if(z==3)return make_pair(y-len,x-len);

偶数

依旧 DFS。

运用 lowbit ,分别递归二的次幂和其余数字即可。

[USACO24JAN] Potion Farming S

本题选择使用树上DP。

\(f_u\) 表示经过 \(u\) 的路径数,等价为 \(u\) 这个子树内 叶子节点的个数
\(dp_u\) 表示 \(u\) 这个子树内得到的最大药水数量。

\(f_u\) DFS 跑一遍就行了;

接着, \(dp_u\) 初始值设为 \(dp_{a_i}=1\) ,其中 \(1≤i≤\) 总叶子结点个数。

然后,对于 \(dp_u\) ,我们将 \(u\) 的每一个子树的结果加起来。但是,注意到每一次遍历都最多只能获得一瓶药水,而且最多遍历 \(f_u\) 次,所以要取 \(min\)
于是就可以得到状态转移方程为:

\(dp_u=min(\sum_{v∈E_u}dp_v,p_u)\)

所以,最后答案是 \(dp_1\)

[USACO23DEC] Cycle Correspondence S

将谷仓的编号分为 \(3\) 类。
第一类是均不在两个环里的,第二类是只在某一个环里的,第三类是在两个环里的。

第一类的所有编号显然都算上。

第二类的显然都不能算上。

第三类的编号需要考虑顺序。设 \(m\) 表示 \(a\) 编号方式下给定的环的输入顺序的第一个谷仓,在 \(b\) 编号方式下输入顺序的位置。
然后扫描一下所有第三类的编号,计算出如果这个编号在两种编号方式下对应的两个谷仓如果相同,那么 \(m\) 应该是多少,加到桶里,最后取个数最多的 \(m\) 即可。

三分

三分求单峰函数极值板子。

三分和二分很像,但是三分和二分的不同在于二分只取一个 mid 但是三分要取两个点 lmidrmid
lmid & rmid 的代码:

 double lmid=l+(r-l)/3;
 double rmid=r-(r-l)/3;

接下来的操作和二分很像:如果 \(f(lmid)<=f(rmid)\) ,就令 \(l=lmid\) ;否则 \(r=rmid\)

最后输出 \(r\) 即可。

另外,本题对精度要求不高,eps=1e-8 就够了。

posted @ 2026-05-12 20:40  Tri_Function  阅读(3)  评论(0)    收藏  举报