首页 > 其他分享 > [RC-03] 记忆

[RC-03] 记忆

时间:2023-11-02 15:57:43浏览次数:28  
标签:03 ch RC 矩阵 记忆 bmatrix ans 操作 我们

prologue

今天模拟赛 T3,一道很好的题目。

analysis

对于这个题目我们可以通过对操作的手玩,得出一个结论。

记 \(ans\) 为当前所有的合法子串数量,记 \(tmp\) 为当前以最后以一个括号结尾的子串个数。可以推出来前两个操作分别的转移式子:

\[ans \gets ans + tmp + 1,p \gets p + 1 \]

\[ans \gets ans + 1, p \gets 1 \]

感觉这个证明起来其实很显然,读者自证不难简单证明一下:

  1. 如果是操作 1,我们在最后面加上一个合法的匹配括号,就相当于是在继承了父亲(上一个状态)的条件下,又多了一对括号。所以得出来第一个式子。

  2. 如果是操作2,我们在当前的串加上一个最外层的括号。这相当于是自断一臂,因为我们此时再去统计以最后一个括号为结尾的子串,就只有前面这一坨了(傻鱼的量词是跟初中历史老师学的),我们最后的 \(ans\) 也就仅仅只是加上了前面这一整串这个答案,所以推出来第二个式子。(其实你可以看成二号操作是对前面的串进行了整个的封装。)

然后我们开始考虑怎么去维护上面两个操作。

我们上面的式子是非常具有矩阵转移的性质的,即我们可以构造这样一个 \(\begin{bmatrix}ans, tmp, 1\end{bmatrix}\) 的答案矩阵,那么我们上面两个操作的矩阵也就可以构造出来了

  1. 操作一的转移矩阵: \(\begin{bmatrix}1 & 0 & 0 \\ 0 & 1 & 0 \\ 1 & 1 & 1\end{bmatrix}\)

  2. 操作二的转移矩阵:\(\begin{bmatrix} 1 & 0 & 0 \\ 0 & 0 & 0 \\ 1 & 1 & 1\end{bmatrix}\)

但是我们不可能对于每一次操作都 \(O(n)\) 扫一遍,而且还有单点修改,还要滚回去撤销操作,所以我们再考虑:

我们知道矩阵乘法是具有结合律的,即 \(A_1 A_2 A_3 = A_1(A_2 A_3)\) 所以我们的答案矩阵只需要左乘一次后面整体矩阵的乘积就好了。

我们就可以用线段树来进行这个单点修改,区间查询(查询后面所有操作的乘积)的操作。(单位矩阵对于矩阵乘法没有贡献所以我们就可以那这个当作我们的初始值了)

我们上面两个操作的思路就呼之欲出了,再考虑我们的撤销操作。

我们通过分析样例可以知道,我们的撤销操作是可以撤销之前的撤销操作的。所以我们对于一个地方的修改不可能是真的就给撤销没了,我们就可以考虑每个操作节点维护两个矩阵,一个单位矩阵 \(B\) 一个贡献矩阵 \(A\) 每次撤销操作就是 \(swap(A, B)\) 的过程。

而对于这个撤销撤销操作不就是找到自己的爹的爹么,可以用并查集来维护。(这里加粗是为了方便断句)

分析至此,接下来就是我们的代码实现了。

code time

火车头自跳。

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define rl register ll
#define fom(i, a) for(rl i=a; i; -- i)
#define foa(i, a, b) for(rl i=a; i < b; ++ i)
#define fos(i, a, b) for(rl i=a; i <= b; ++ i)
#define fop(i, a, b) for(rl i=a; i >= b; -- i)
namespace IO
{
    int pp1=-1; const int pp2=(1<<21)-1; char buf[1<<21],*p1=buf,*p2=buf,buffer[1<<21];
    inline void flush() {fwrite(buffer,1,pp1+1,stdout); pp1=-1;}
    inline void pc(const char ch) {if(pp1==pp2) flush(); buffer[++pp1]=ch;}
    inline char gc(){ return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
    template <class T> inline void read(T &res){char ch=gc();bool f=0;res=0; for(;!isdigit(ch);ch=gc()) f|=ch=='-'; for(;isdigit(ch);ch=gc()) res=(res<<1)+(res<<3)+(ch^48); res=f?~res+1:res;}
    template <class T> inline void ww(T x) { if(!x) pc('0'); else { static int stk[21]; int top = 0; if(x<0) pc('-'),x=~x+1; while(x) stk[top++]=x%10, x/=10; while(top--) pc(stk[top]^48);}}
}

#define wp IO::pc(' ')
#define wl IO::pc('\n')
#define ww(x) IO::ww(x)
#define read(x) IO::read(x)
#define flush() IO::flush()

constexpr ll N  = 2e5 + 10;

ll n, p[N];

struct Matrix
{
    ll a[4][4];

    Matrix () { memset(a, 0, sizeof a);} 

    inline void make_I() { fos(i, 1, 3) a[i][i] = 1; }

    inline void init() { fos(i, 1, 3) a[1][i] = 1; }

    Matrix operator *(const Matrix &x) const
    {
        Matrix res;

        fos(i, 1, 3) fos(k, 1, 3) fos(j, 1, 3)  
            res.a[i][j] += a[i][k] * x.a[k][j];

        return res; 
    }

    inline void print()
    {
        fos(i, 1, 3)
        {
            fos(j, 1, 3) ww(a[i][j]), wp;

            wl;
        }
    }
} I, Op1, Op2, ans;

struct tree
{
    ll l, r;
    Matrix A, B;
} tr[N << 2];

inline ll find(ll x) { return p[x] == x ? x : p[x] = find(p[x]); }

inline void pushup(ll u) { tr[u].A = tr[u << 1].A * tr[u << 1 | 1].A; }

inline void build(ll u, ll l, ll r)
{
    tr[u] = {l, r, I, I}; 

    if(l == r) return ;
    
    ll mid = l + r >> 1;

    build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
    pushup(u);
}

inline void update(ll u, ll x, ll op)
{
    if(tr[u].l == tr[u].r && tr[u].l == x)
    {
        if(op == 1) tr[u].A = Op1;
        if(op == 2) tr[u].A = Op2;
        return ;
    }

    ll mid = tr[u].l + tr[u].r >> 1;

    if(x <= mid) update(u << 1, x, op);
    if(x > mid) update(u << 1 | 1, x, op);

    pushup(u);
}

inline void remove(ll u, ll x)
{
    if(tr[u].l == x && tr[u].r == x)
    {
        swap(tr[u].A, tr[u].B);
        return;
    }

    ll mid = tr[u].l + tr[u].r >> 1;

    if(x <= mid) remove(u << 1, x);
    if(x > mid) remove(u << 1 | 1, x);
    pushup(u);
}

int main()
{
    // freopen("dydy.in", "r", stdin), freopen("dydy.out", "w", stdout);
    read(n); I.make_I(), Op1.make_I(), Op2.make_I();

    fos(i, 1, n) p[i] = i;

    Op2.a[2][2] = 0;
    Op1.a[2][1] = Op1.a[3][1] = Op1.a[3][2] = Op2.a[3][2] = Op2.a[3][1] = 1;

    build(1, 1, n);

    fos(i, 1, n)
    {
        ans.init();
        ll op, x; read(op);
        if(op == 1 || op == 2) update(1, i, op);
        else { read(x); remove(1, find(x)); p[i] = x; }
        ans = ans * tr[1].A;
        ww(ans.a[1][1]), wl;
    }
    flush(); return 0;
}

标签:03,ch,RC,矩阵,记忆,bmatrix,ans,操作,我们
From: https://www.cnblogs.com/carp-oier/p/P6864.html

相关文章

  • 喜讯!INFINI Easysearch 在墨天轮数据库排名中挺进前30!
    近日,2023年10月的墨天轮中国数据库流行度排行火热出炉,本月共有283个数据库参与排名,中国数据库行业竞争日益激烈。其中,极限科技旗下软件产品INFINIEasysearch稳步推进,在国内整个数据库排行中进入了前30的行列!同时在搜索型数据库分类排名中保持领先,稳住了第一名的......
  • 【深度学习】PyTorch的基本运算 与 构造简单神经网络模型
    基本运算importtorch#创建一个自定义的张量t=torch.tensor([1.0,2.0,3.0])#tensor([1.,2.,3.])#求平均值t.mean()#tensor(2.)#创建一个指定行列的张量x=torch.empty(3,5)#tensor([[0.,0.,0.,0.,0.],[0.,0.,0.,0.,0.],[0.,0.,0.,0.,0.]......
  • linux CentOS ModuleNotFoundError: No module named '_ctypes
    Yesthatworkedforme,ImadesurethesepackagesareinstalledonmyCentos7:sudoyuminstall-yzlib-develbzip2-developenssl-develncurses-develsqlite-develreadline-develtk-develgdbm-develdb4-devellibpcap-develxz-develexpat-devellibffi-dev......
  • Codeforces Round 906 (Div. 2)
    CodeforcesRound906(Div.2)比赛链接A.Doremy'sPaint3题目链接判断给定的数组是不是满足a1+a2=a2+a3=a3+a4=......=an-1+anA思路:这个题一开始没有读仔细问题,导致一时间出错了,后来读清楚问题之后发现其实这个数组中只能出现两个数字,且两个数字之间的差值最多是1A代码:......
  • javamail发送附件DataSource使用文件流解决方案
    问题:在使用james邮件服务器发送邮件时,附件是存储在华为云服务器上的,只能通过ApacheHttpClient去下载,存储在FTP上的文件同样会碰到这个问题。API上邮件添加附件的方法:/*************1.本地文件*************///将本地文件作为附件DataSourcedataSource=newFileDataSourc......
  • [ARC159F] Good Division 题解
    [ARC159F]GoodDivision题解首先对于题目要求的划分方式转化一下,转化为划分的每一段都没有绝对众数,可以证明这与题目中的要求是完全等价的,证明如下:充分性:考虑构造一种操作方法,就是每次操作都消去一个出现次数最多的数,按照这样操作可以保证每次操作之后该区间仍然不会出现绝对......
  • Spring byName和byType两种注入方式;@Resource和@Autowired
    Spring控制翻转IOC可以理解为一个类,依赖注入可以理解为一个对象控制反转(IoC)是一个通用的概念,它可以用许多不同的方式去表达,依赖注入仅仅是控制反转的一个具体的例子。依赖注入的2种方法:1、构造函数依赖注入2、setter方法依赖注入自动装配分为3种:(Spring的byType、byName......
  • Keras TypeError: ('Keyword argument not understood:', 'input')
    TypeError:('Keywordargumentnotunderstood:','input') model=Model(input=[inputs],output=output)报错信息TypeError:('Keywordargumentnotunderstood:','input')解决方法换成model=Model(inputs=...,outputs=...) ......
  • Not creating XLA devices, tf_xla_enable_xla_devices not set TypeError: 'mod
     2021-02-2622:54:13.146272:Itensorflow/core/common_runtime/gpu/gpu_device.cc:1406]CreatedTensorFlowdevice(/job:localhost/replica:0/task:0/device:GPU:0with2989MBmemory)->physicalGPU(device:0,name:GeForceGTX1050,pcibusid:0000:01:0......
  • KEIL软件的Error: Flash Download failed - Could not load file '..\OBJ\Template.
    Error:FlashDownloadfailed - Couldnotloadfile'..\OBJ\USART.axf' 解决方案:1重新覆盖安装keil2程序编译存在错误导致 同时开多个KEIL,只有其中一个KEIL可以使用J-LINK,ST-LINK。 ......