2022/3/22

142 篇文章 1 订阅
142 篇文章 0 订阅

p1383 主席树

这个题比p3919多了一个撤销的操作,需要开一个cnt数组来存一下每个历史版本最后一个字母所在的位置,这样添加的时候就只要cnt[tot]=cnt[tot-1]+1就可以准确的找到该在哪添加这个位置了;

题解 P1383 【高级打字机】 - lukelin 的博客 - 洛谷博客 (luogu.com.cn)

#include <bits/stdc++.h>
#define ll long long
#define lowbit(a) (a&(-a))
using namespace std;
const int mod=1000003;
const int inf=0x3f3f3f3f;
ll qpow(ll a,ll b){
    ll res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
ll getinv(ll a,ll mod){return qpow(a,mod-2);}
ll n,top,m,a[1000006],op,root[1000006*35],cnt[100005];
struct Node{
    ll l,r;
    char val;
}t[1000006*35];
ll clone(ll node){
    top++;
    t[top]=t[node];
    return top;
}
ll maketree(ll node,ll l,ll r){
    node=++top;
    if(l==r){
        t[node].val='0';
        return top;
    }
    ll mid=l+r>>1;
    t[node].l=maketree(t[node].l,l,mid);
    t[node].r=maketree(t[node].r,mid+1,r);
    return node;
}
ll update(ll node,ll l,ll r,ll x,char val){
    node=clone(node);
    if(l==r) t[node].val=val;
    else{
        ll mid=l+r>>1;
        if(x<=mid) t[node].l=update(t[node].l,l,mid,x,val);
        else t[node].r=update(t[node].r,mid+1,r,x,val);
    }
    return node;
}
char query(ll node,ll l,ll r,ll x){
    if(l==r) return t[node].val;
    else{
        ll mid=l+r>>1;
        if(x<=mid) return query(t[node].l,l,mid,x);
        else return query(t[node].r,mid+1,r,x);
    }
}
int main(){
   //freopen("in.txt","r",stdin);
   scanf("%lld",&n);
   root[0]=maketree(0,1,n);
   ll tot=0;
   for(int i=1;i<=n;i++){
    char op;
    cin>>op;
    if(op=='T'){
        char x;
        cin>>x;
        tot++;
        cnt[tot]=cnt[tot-1]+1;
        root[tot]=update(root[tot-1],1,n,cnt[tot],x);
    }
    else if(op=='U'){
        ll x;
        scanf("%lld",&x);
        tot++;
        root[tot]=root[tot-x-1>0?tot-x-1:0];//注意越界
        cnt[tot]=cnt[tot-x-1?tot-x-1:0];
    }
    else{
        ll x;
        scanf("%lld",&x);
        printf("%c\n",query(root[tot],1,n,x));
        //root[i]=root[i-1];
    }
   }
    return 0;
}

p4555 马拉车算法

要求将一个串拆成两个串,求两个串回文串的长度和最大;一开始就想的是马拉车算法求出以i点为半径的最大回文串的长度,然后开始n方枚举,这肯定不对,抱着侥幸心理交了一发就对了1个点,,,然后看题解之后原来是要枚举‘#’,’#‘之前的加上之后的,遍历一遍取最大,为此需要再开两个数组,l[i]代表以i为结尾的最长回文串的长度,r[i]代表以i为开头的最长回文串的长度,可以在马拉车算法过程中求得,但是求得不够全,r[i]只是求了以i为开头的最长回文的长度,而别的都没求,就比如i+1可能就没求到,但r[i+1]的长度至少是r[i]-2的;所以后面还要完整的求一遍;

这个人也讲了为什么要求再完整的求一遍

题解 P4555 【[国家集训队]最长双回文串】 - 初音ミク的博客 - 洛谷博客 (luogu.com.cn)

这是题解题解 P4555 【最长双回文串】 - 浅色调 的博客 - 洛谷博客 (luogu.com.cn)

#include <bits/stdc++.h>
#define ll long long
#define lowbit(a) (a&(-a))
using namespace std;
const int mod=1000003;
const int inf=0x3f3f3f3f;
ll qpow(ll a,ll b){
    ll res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
ll getinv(ll a,ll mod){return qpow(a,mod-2);}
ll len,n,cnt=0,m;
ll p[200100],l[200100],r[200100];
string s,str;
void manachar(){
     str="$#";
    for(int i=0;i<len;i++){
        str+=s[i];str+="#";
    }
    m=str.size();

    ll id=0,mx=0;
    for(int i=1;i<m;i++){
        p[i]=mx>i?min(p[id*2-i],mx-i):1LL;
        while(str[i+p[i]]==str[i-p[i]]) p[i]++;
        if(i+p[i]>mx){
            mx=p[i]+i;
            id=i;
        }
        l[i+p[i]-1]=max(l[i+p[i]-1],p[i]-1);
        r[i-p[i]+1]=max(r[i-p[i]+1],p[i]-1);
    }
}
int main(){
   //freopen("in.txt","r",stdin);
    cin>>s;
    len=s.size();
    manachar();
    ll ans=0;
    //for(int i=1;i<m;i++) cout<<l[i]<<" "<<r[i]<<" "<<p[i]<<endl;
    for(int i=1;i<m;i+=2) r[i]=max(r[i],r[i-2]-2);
    for(int i=m-1;i>=1;i-=2) l[i]=max(l[i],l[i+2]-2);
    for(int i=1;i<m;i+=2) if(l[i]&&r[i]) ans=max(ans,l[i]+r[i]);//aba 不判零的话就会是3
    printf("%lld",ans);
    return 0;
}

p1659 马拉车算法

只要统计出每个奇数长度回文串出现的次数,然后挑前k长的乘起来取余就行;但是有个坑点:如果有一个回文串长度为7,那么他也包括长度为5和长度为3的,而这两个马拉车是不能直接算出来的,所以算的时候也要统计上,,哎,除了这一点还被自己的代码给坑了,,

题解 P1659 【[国家集训队]拉拉队排练】 - 三好代表 的博客 - 洛谷博客 (luogu.com.cn)

#include <bits/stdc++.h>
#define ll long long
#define lowbit(a) (a&(-a))
using namespace std;
const ll mod=19930726;
const int inf=0x3f3f3f3f;
ll qpow(ll a,ll b){
    ll res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
ll getinv(ll a,ll mod){return qpow(a,mod-2);}
ll len,n,k,m;
ll p[2001000],maxx;
map<ll,ll>mp;
string s,str;
void manachar(){
     str="$#";
    for(int i=0;i<len;i++){
        str+=s[i];str+="#";
    }
    m=str.size();

    ll id=0,mx=0;
    for(int i=1;i<m;i++){
        p[i]=mx>i?min(p[id*2-i],mx-i):1LL;
        while(str[i+p[i]]==str[i-p[i]]) p[i]++;
        if(i+p[i]>mx){
            mx=p[i]+i;
            id=i;
        }
        if((p[i]-1)%2){
            maxx=max(maxx,p[i]-1);
            mp[p[i]-1]++;
        }
    }
}
int main(){
   //freopen("in.txt","r",stdin);
    scanf("%lld%lld",&n,&k);
    cin>>s;
    len=s.size();maxx=0;
    manachar();
    ll mul=1,cnt=0;
    for(int i=maxx;i>=1;i-=2){
        //if(mp[i]<=0) continue; 如果一个回文串长度为7,这样就不能统计长度为5或3的了
        //究竟是多迷糊的脑子才能写出上面这一句话来。。。
        cnt+=mp[i];
        if(cnt>=k){mul=(mul*qpow(i,k))%mod;k-=k;break;}
        else{mul=(mul*qpow(i,cnt))%mod;k-=cnt;}
    }
    if(k>0) printf("-1\n");
    else printf("%lld\n",mul);
    return 0;
}

I - Invoking the Magic   优先队列

也可以用并查集做,但我并查集不熟,,,一对一对的输入,定义一个结构体x,y,cnt(初始化为1)代表第一支袜子,第二支袜子,到达这个x,y的状态一共花了几组袜子,保证x小于等于y,这样就可以进到优先队列里去,我们每次都拿出两组来,可以发现这两组的x是一定相同的,我们只要看看y相不相同就行,相同就记录一下容量最大值,不相同就让这两组中的较小y当新的x,较大y当新的y再次进入队列;然后再说说.cnt的作用,每次合并时,设一个变量ct等于这两组的cnt之和,代表这两组袜子是ct组袜子组合来的,这样就可以记录容量了;

#include<bits/stdc++.h>
#include<string>
#define ll long long
using namespace std;
const int maxn =3e7+5;
ll t,n;
struct node{
    ll x,y,cnt;
    bool operator<(const node &a)const{
        if(a.x==x) return a.y<y;
        return a.x<x;
    }
}a[100005];
priority_queue<node>q;
int main() {
    //freopen("in.txt","r",stdin);
	scanf("%lld",&t);
	while(t--){
        scanf("%lld",&n);
        for(int i=1;i<=n;i++){
            scanf("%lld%lld",&a[i].x,&a[i].y);
            if(a[i].x>a[i].y) swap(a[i].x,a[i].y);
            a[i].cnt=1;
            q.push(a[i]);
        }
        ll maxx=1;
        while(!q.empty()&&q.top().x==q.top().y) q.pop();
        while(!q.empty()){
            while(!q.empty()&&q.top().x==q.top().y) q.pop();
            if(q.empty()) break;
            node now=q.top();q.pop();
            node u=q.top();q.pop();
            ll ct;
            ct=u.cnt+now.cnt;
            node tmp;
            if(now.x==u.x&&now.y==u.y){maxx=max(maxx,ct);continue;}
            if(now.y<u.y) tmp.x=now.y,tmp.y=u.y;
            else tmp.x=u.y,tmp.y=now.y;
            tmp.cnt=ct;
            q.push(tmp);
        }
        printf("%lld\n",maxx);
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

killer_queen4804

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值