[JZOJ]杂讲选题——第二弹

这篇博客详细介绍了JZOJ竞赛中涉及的线段树应用、括号匹配算法和数组优化问题。通过多个实例解析,包括线段树的构建与查询、括号序列的合法性检查以及哈夫曼树的应用,帮助读者理解和解决相关算法题。此外,还讨论了等比数列求和、最优化路径选择和棋盘路径问题的解法,提供了完整的代码实现。
摘要由CSDN通过智能技术生成

1.线段树什么的最讨厌了

Description

小Y 最近学习了线段树,但是由于她的智商比较低,运用的还不是很熟练。于是小R 给了她一点练习题训练,其中有一道是这样的。
这是小R 写的线段树的一段建树代码:

只要调用 b u i l d t r e e ( 1 , 0 , n ) buildtree(1,0,n) buildtree(1,0,n) 就可以得到一颗线段树了。显然,一颗线段树一共有 O ( n ) O(n) O(n) 个节点,因为每一个节点都代表了一个不同的区间,所以线段树上一共出现了 O ( n ) O(n) O(n) 个不同的区间。
现在小R 给了你一个区间 [ l , r ] [l,r] [l,r],他想要你告诉他一个最小的 n n n使得区间 [ l , r ] [l,r] [l,r]出现在了用 b u i l d t r e e ( 1 , 0 , n ) buildtree(1,0,n) buildtree(1,0,n)建出来的线段树中。

Input

第一行输入一个正整数 T T T表示数据组数。
接下来 T T T行每行三个整数 L L L, R R R, l i m lim lim 表示一组询问,如果对于所有的 0 ≤ 0 \leq 0 n n n ≤ \leq l i m lim lim 都不存在满足条件的解,输出 − 1 -1 1即可。

Output

对于每组询问输出一个答案。

Data Constraint

Solutions

可以发现 [ L , R ] [L, R] [L,R] 的父节点代表的区间至多有 4 4 4 种,分别为 [ L , 2 R − L ] , [ L , 2 R − L + 1 ] , [ 2 L − R − 2 , R ] , [ 2 L − R − 1 , R ] [L, 2R−L], [L, 2R−L+ 1], [2L−R − 2, R], [2L − R − 1, R] [L,2RL],[L,2RL+1],[2LR2,R],[2LR1,R],所以只需要暴力枚举这些搜下去就好了,当两端超出限制的时候退出。
可以发现,每一搜索一次, L R − L + 1 \frac{L}{R−L+1} RL+1L 都至少除以 2 2 2,所以搜索的复杂度应该为 O ( ( L R − L + 1 ) 2 ) O((\frac{L}{R−L+1})^2) O((RL+1L)2),这是可以在时间范围内跑出来的。

Code

#include <cstdio>
const int N = 2e9 + 10;
int ans,L,R,lim;
void dfs(int l,int r) 
{
   
    if (r > lim) return;
    if (r >= ans) return;
    if (l == 0) 
	{
   
        ans = r;
        return;
    }
    int cnt = r - l + 1;
    if (l - cnt == 0 || l - cnt >= cnt + cnt) dfs(l - cnt,r);
    if (l - cnt == 1 || l - cnt - 1 >= cnt + cnt + 1) 
		dfs(l - cnt - 1,r);
    if (l >= cnt + cnt - 1) dfs(l,r + cnt - 1);
    if (l > cnt + cnt) dfs(l,r + cnt);

}
int main() 
{
   
    int T;
    scanf("%d",&T);
    while (T --) 
	{
   
        scanf("%d%d%d",&L,&R,&lim);
        ans = N;
        dfs(L,R);
        if (ans == N) printf("-1\n");
        else printf("%d\n",ans);
    }
}

2.已经没有什么好害怕的了

Description

小Y 最近开始学习算法姿势,但是因为小R 非常BB,给了她很多B6 题,所以她觉得自己已经没有什么前途了。于是小R 给了她一些稍微简单的题,让她觉得已经没有什么好害怕的了,其中一道是这样的:
给定一个长度为n 只包含左括号和右括号的序列,现在小R 想要知道经过每一个位置的合法子串有多少个。
空串是一个合法的串,如果A 和B 都是合法的串,那么(A) 和AB 都是合法的串。

Input

第一行输入一个正整数T 表示数据组数。接下来T 行每行一个字符串。

Output

对于每组数据,输出一个整数表示答案,令ansi 为经过第i 个位置的子串个数,那么你需要输出 ∑ i = 1 n ( i ∗ a n s i m o d &ThinSpace;&ThinSpace; ( 1 e 9 + 7 ) ) \sum^{n}_{i=1}(i*ans_i\mod (1e9+7)) i=1n(iansimod(1e9+7))(注意是先求余再求和)

Data Constraint

对于 10 10% 10的数据, n &lt; = 100 n&lt;=100 n<=100
对于 30 30% 30 的数据, n &lt; = 1000 n &lt;= 1000 n<=1000
对于 60 60% 60的数据, n &lt; = 5 &lt; = 1 0 4 n &lt;= 5 &lt;= 10^4 n<=5<=104
对于 100 100% 100的数据, n &lt; = 1 0 6 , 1 &lt; = T &lt; = 10 n &lt;= 10^6,1 &lt;= T&lt;= 10 n<=1061<=T<=10

Solutions

又是差分的题目,非常坑先给括号配对,让后记一对合法的括号为 [ l , r ) [l,r) [l,r)我们分别按顺序和倒序处理每对括号 [ l , r ) [l,r) [l,r),对于括号 [ l , r ) [l,r) [l,r),我们先对区间 [ l , r ) [l,r) [l,r)加上 1 1 1,让后考虑它的影响若 l l l是另一对括号 [ l ′ , r ′ ) [l&#x27;,r&#x27;) [l,r)的右端点(r’=l)那么显然这里的 [ l , r ) [l,r) [l,r)贡献可以全部加过去,若 r r r是另一对括号 [ l ′ , r ′ ) [l&#x27;,r&#x27;) [l,r)的左端点,那么显然也可以把 [ l , r ) [l,r) [l,r)的贡献全加过去,不合法的括号位置会自动抵消

Code

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 1000010
#define M 1000000007
using namespace std;
long long ans,f[N]; char s[N];
int n,m,t,w[N],l[N],r[N],cl[N],cr[N];
int _18520(){
   
	scanf("%s",s+1); n=strlen(s+1);
	for(int i=1;i<=n;++i)
		if(s[i]=='(') w[++t]=i;
		else if(t){
    r[w[t]]=i+1; l[i+1]=w[t--]; }
	for(int i=n+1;i;--i) cr[l[i]]+=++cr[i];
	for(int i=1;i<=n;++i) cl[r[i]]+=--cl[i];
	for(int i=1;i<=n;++i) f[i]=f[i-1]+cl[i]+cr[i];
	for(int i=1;i<=n;++i) ans=ans+i*f[i]%M;
	printf("%lld\n",ans);
}
int main(){
   
	int T; 
	for(scanf("%d",&T);T--;_18520()){
   
		memset(f,0,N<<3);
		memset(l,0,N<<2);
		memset(r,0,N<<2);
		memset(cl,0,N<<2);
		memset(cr,0,N<<2);
		t=ans=0;
	}
}

3.我才不是萝莉控呢

Description

小Y:“小R 你是萝莉控吗。”小R:“…”
为了避免这个尴尬的话题,小R 决定给小Y 做一道题。
有一个长度为 n n n 的正整数数组A,满足 A i &gt; = A i + 1 Ai &gt;= Ai+1 Ai>=Ai+1,现在构造一个数组B,令 B i Bi Bi= ∑ n i a \sum\limits^{i}_{n}a nia
现在,有一个

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值