NOIP模拟14「队长快跑·影魔·抛硬币」
T1:队长快跑
基本思路:
  离散化·DP·数据结构优化DP
  这三个我都没想到。。。。气死。
  定义状态数组:\(c[i][j]\)表示在i时最小的a值是j时可以摧毁的最多的水晶数。
  那么状态转移方程就是:
c[i][j]=max(c[i-1][a[i]+1],c[i-1][a[i]+2],......,c[i-1][maxn])+1,if(a[i]>b[i]),这时还要同时更新c[i-1][j](j\(\in(b[i],a[i]]\))
c[i][j]=max(c[i-1][b[i]+1],c[i-1][b[i]+2],......,c[i-1][maxn])+1,if(a[i]<=b[i])
我来解释下为什么这么转移:
首先可以明确的一点是,c[i][a[i]]只能由c[i-1][a[i]+1->maxn]转移来,因为如果转移的j比a[i]小,那么转移来的情况就不是以a[i]为最小值了。
加一是将当前点纳入
当a[i]<=b[i]时,我解释下什么是b[i]+1而不是a[i]+1,因为题目要求是之前的a比现在的b大,所以这么转移才合法
当a[i]>b[i]时,在b[i]~a[i]的范围内,c[i-1]是可以将当前点纳入的,所以要给他们集体加一,c[i][a[i]的转移就很好理解了
  直接转移时间复杂度是\(O(n^{3})\),考虑优化,我们可以将第二维放在线段树上,对应的叶子维护对应a值情况的值,一棵线段树从头用到尾,记录的是当前的情况,就可以\(O(nlogn)\)转移了。
  上代码:
#include<bits/stdc++.h>
using namespace std;
namespace STD
{
    #define ll long long
    #define rr register
    inline int max(int x,int y){return x>y?x:y;}
	//伤心往事:
	//这里的max原本用的是#define函数,然后TLE了
	//后来小马告诉我,#define函数会重复调用,T到起飞
	//所以改成了inline
    const int SIZE=100002;
    int n;
    int a[SIZE],b[SIZE];
    int c[SIZE<<1];
    int read()
    {
        rr int x_read=0,y_read=1;
        rr int c_read=getchar();
        while(c_read<'0'||c_read>'9')
        {
            if(c_read=='-') y_read=-1;
            c_read=getchar();
        }
        while(c_read<='9'&&c_read>='0')
        {
            x_read=(x_read*10)+(c_read^48);
            c_read=getchar();
        }
        return x_read*y_read;
    }
    int lazy[SIZE<<3],maxn[SIZE<<3];
    void push_down(int id)
    {
        if(!lazy[id]) return;
        lazy[id<<1]+=lazy[id],lazy[id<<1|1]+=lazy[id];
        maxn[id<<1]+=lazy[id],maxn[id<<1|1]+=lazy[id];
        lazy[id]=0;
        return;
    }
    void add(int id,int l,int r,int st,int en,int val)
    {
        if(st<=l&&r<=en){maxn[id]+=val,lazy[id]+=val;return;}
        int mid=(l+r)>>1;
        push_down(id);
        if(st<=mid) add(id<<1,l,mid,st,en,val);
        if(mid<en) add(id<<1|1,mid+1,r,st,en,val);
        maxn[id]=max(maxn[id<<1],maxn[id<<1|1]);
    }
    void change(int id,int l,int r,int pos,int val)
    {
        if(l==r){maxn[id]=max(maxn[id],val);return;}
        int mid=(l+r)>>1;
        push_down(id);
        if(pos<=mid) change(id<<1,l,mid,pos,val);
        else change(id<<1|1,mid+1,r,pos,val);
        maxn[id]=max(maxn[id<<1],maxn[id<<1|1]);
    }
    int query(int id,int l,int r,int st,int en)
    {
        if(st<=l&&r<=en) return maxn[id];
        int mid=(l+r)>>1;
        int ret=INT_MIN;
        push_down(id);
        if(st<=mid) ret=max(ret,query(id<<1,l,mid,st,en));
        if(mid<en) ret=max(ret,query(id<<1|1,mid+1,r,st,en));
        return ret;
    }
};
using namespace STD;
int main()
{
    n=read();
    for(rr int i=1;i<=n;i++)
    {
        a[i]=read(),b[i]=read();
        c[++c[0]]=a[i],c[++c[0]]=b[i];
    }
    sort(c+1,c+1+c[0]);
    int cnt=unique(c+1,c+1+c[0])-c-1;
    for(rr int i=1;i<=n;i++)
    {
        a[i]=lower_bound(c+1,c+1+cnt,a[i])-c;
        b[i]=lower_bound(c+1,c+1+cnt,b[i])-c;
    }
    int val;
    for(rr int i=1;i<=n;i++)
    {
        if((a[i]<=b[i])&&(b[i]+1<=cnt))
        {
            val=query(1,1,cnt,b[i]+1,cnt)+1;
            change(1,1,cnt,a[i],val);
        }
        if(a[i]>b[i])
        {
            add(1,1,cnt,b[i]+1,a[i],1);
			//注意要先add后change,因为change后的树现在的情况了
			//而add是给之前的情况add
            if(a[i]+1<=cnt)
            {
                val=query(1,1,cnt,a[i]+1,cnt)+1;
                change(1,1,cnt,a[i],val);
            }
        }
    }
    printf("%d",maxn[1]);
}
T2:影魔
由于要用到可持久化线段树,我们没学,先鸽掉。
T3:抛硬币
基本思路:
  一个简单的小DP。
  定义状态数组:\(c[i][j]\)表示在i位置长度为j的本质不同的子序列的个数。
  很容易想出方程\(c[i][j]=c[i-1][j-1]+c[i-1][j]\)c[i-1][j-1]是新形成了这么多串,c[i-1][j]是继承之前已经形成了的串、
  但是一看样例,事情并不简单,有的字母重复出现,就会导致序列算重,因此要记录每个字母上一次出想的位置last。
  最终的方程是:
\]
上代码:
#include<bits/stdc++.h>
using namespace std;
namespace STD
{
    #define ll long long
    #define rr register
    const int SIZE=3001;
    const int mod=998244353;
    int l;
    char s[SIZE];
    int c[SIZE][SIZE];
    int last[29];
    int read()
    {
        rr int x_read=0,y_read=1;
        rr char c_read=getchar();
        while(c_read<'0'||c_read>'9')
        {
            if(c_read=='-') y_read=-1;
            c_read=getchar();
        }
        while(c_read<='9'&&c_read>='0')
        {
            x_read=(x_read*10)+(c_read^48);
            c_read=getchar();
        }
        return x_read*y_read;
    }
};
using namespace STD;
int main()
{
    int x=scanf("%s",s+1);
    int len=strlen(s+1);
    l=read();
    c[1][1]=1;
    for(rr int i=0;i<=len;i++) c[i][0]=1;
    last[s[1]-'a'+1]=1;
    for(rr int i=2;i<=len;i++)
    {
        for(rr int j=1;j<=l;j++)
        {
            if(j>i) break;
            if(last[s[i]-'a'+1])
                c[i][j]=((c[i-1][j]+c[i-1][j-1])%mod-c[last[s[i]-'a'+1]-1][j-1]+mod)%mod;
            else
                c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
        }
        last[s[i]-'a'+1]=i;
    }
    printf("%d",c[len][l]);
}
												
											NOIP模拟14「队长快跑·影魔·抛硬币」的更多相关文章
- NOIP 模拟 $14\; \text{队长快跑}$
		
题解 \(by\;zj\varphi\) 一道很妙的 \(dp\) 题,方程状态不好设置,细节也不少 看到数据范围,直接想离散化 设 \(f_{i,j}\) 表示处理完前 \(i\) 个水晶,其中摧毁 ...
 - HZOI20190908模拟40 队长快跑,影魔,抛硬币 题解
		
题面:https://www.cnblogs.com/Juve/articles/11487699.html 队长快跑: 权值线段树与dp yy的不错 #include<iostream> ...
 - [LOJ 2022]「AHOI / HNOI2017」队长快跑
		
[LOJ 2022]「AHOI / HNOI2017」队长快跑 链接 链接 题解 不难看出,除了影响到起点和终点的射线以外,射线的角度没有意义,因为如果一定要从该射线的射出一侧过去,必然会撞到射线 因 ...
 - Noip模拟14 2021.7.13
		
T1 队长快跑 本身dp就不强的小马看到这题并未反映过来是个dp(可能是跟题面太过于像那个黑题的队长快跑相似) 总之,基础dp也没搞出来,不过这题倒是启发了小马以后考试要往dp哪里想想 $dp_{i, ...
 - BZOJ4829: [Hnoi2017]队长快跑
		
BZOJ4829: [Hnoi2017]队长快跑 Description 众所周知,在P国外不远处盘踞着巨龙大Y. 传说中,在远古时代,巨龙大Y将P国的镇国之宝窃走并藏在了其巢穴中,这吸引着整个P国的 ...
 - [CSP-S模拟测试]:队长快跑(DP+离散化+线段树)
		
题目背景 传说中,在远古时代,巨龙大$Y$将$P$国的镇国之宝窃走并藏在了其巢穴中,这吸引着整个$P$国的所有冒险家前去夺回,尤其是皇家卫士队的队长小$W$.在$P$国量子科技实验室的帮助下,队长小$ ...
 - NOIP 模拟 $14\; \text{影魔}$
		
题解 \(by\;\;zj\varphi\) 不是原题 一道(对我来说)很需要技巧的题 对于颜色数如何处理 离线,将子树转化为 \(dfs\) 序,但这种做法无法处理深度 我们按照深度加点(可以通过 ...
 - NOIP模拟 14
		
垃圾成绩,一点都不稳定. 如果把数组开小的分得到的话..总分还挺不错.. 那又能怪谁,都快NOIP了还犯这种傻逼错误 nc哥是要阿卡的节奏..真是太强了 某kyh也不知道偷了谁的rp,分高的一批 wd ...
 - [NOIP模拟14]题解
		
当垃圾已经成为一种常态233333 A.旋转子段 考场上的$n^2$手残少了20分,555 (主要是因为实在打不出来$n^3$的做法所以写不了对拍?ccc为什么考场上没有想起有reverse()这么 ...
 
随机推荐
- SimpleDateFormat类的线程安全问题和解决方案
			
摘要:我们就一起看下在高并发下SimpleDateFormat类为何会出现安全问题,以及如何解决SimpleDateFormat类的安全问题. 本文分享自华为云社区<SimpleDateForm ...
 - 自学linux——10.Linux的网络知识
			
linux的网络知识 一.网络相关概述 1.网络的分类 局域网(LAN):在几百米到十几公里内办公楼群或校园内的计算机相互连接所构成的计算机网络 城域网(MAN):覆盖相距不远的几栋办公楼,也可以覆盖 ...
 - 剑指 Offer 29. 顺时针打印矩阵
			
剑指 Offer 29. 顺时针打印矩阵 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字. 示例 1: 输入:matrix = [[1,2,3],[4,5,6],[7,8,9]] 输出: ...
 - 解决ModuleNotFoundError: No module named 'pip'问题
			
Python学习遇到小问题:ModuleNotFoundError: No module named 'pip' 今天想要装一下第三方库exifread的时候发现cmd窗口下无法执行pip命令,想了想 ...
 - C# 事件与继承
			
在窗体编程过程中,常常会封装一个基类,包含未来业务中常用的属性.方法.委托.事件等,但是事件作为一个特殊的委托,只能在声明类中调用,派生类都不可以调用,所以在基类中必须实现一个虚函数,实现事件的调用, ...
 - DNS投毒学习分析总结
			
[一]背景 今晚看一份日志,数据很奇怪.大佬说是DNS投毒,盲点就来了,学习一下~ [二]内容 https://zhuanlan.zhihu.com/p/92899876 看完内容发现属于之前写的DN ...
 - 这个 Redis 连接池的新监控方式针不戳~我再加一点佐料
			
Lettuce 是一个 Redis 连接池,和 Jedis 不一样的是,Lettuce 是主要基于 Netty 以及 ProjectReactor 实现的异步连接池.由于基于 ProjectReact ...
 - 网络安全学习阶段性总结:SQL注入|SSRF攻击|OS命令注入|身份验证漏洞|事物逻辑漏洞|目录遍历漏洞
			
目录 SQL注入 什么是SQL注入? 掌握SQL注入之前需要了解的知识点 SQL注入情况流程分析 有完整的回显报错(最简单的情况)--检索数据: 在HTTP报文中利用注释---危险操作 检索隐藏数据: ...
 - 算法入门 - 动态数组的实现(Java版本)
			
静态数组 Java中最基本的数组大家肯定不会陌生: int[] array = new int[6]; for (int i = 0; i < array.length; i++){ array ...
 - COM笔记-Widows 注册表
			
Widows 注册表 HKEY_CLASSES_ROOT在此关键字之下,可以看到有一个CLSID关键字.在CLSID关键字之下列有系统中安装的所有组件的CLSID.注册表CLSID是一个具有如下格式的 ...