首页 > 其他分享 >[BZOJ3160] 万径人踪灭 题解

[BZOJ3160] 万径人踪灭 题解

时间:2025-01-20 09:00:19浏览次数:1  
标签:BZOJ3160 return int 题解 void 万径 ull comn operator

首先正难则反,想到答案即为满足第一条要求的回文子序列数量,减去回文子串数量。回文子串数量 \(hash+\) 二分即可,考虑前半部分。

假如我们将一个回文子序列一层层剥开,就会发现它其实是由多个相同的字母对拼成的。那么容易想到把字母 \(a\) 和字母 \(b\) 的贡献分开计算。那第一条要求就可以转化为所有字母对中心相同,用 \(FFT\) 计算 \(c_k\),表示所有 \(i+j=k\) 的字母对数量即可。

时间复杂度 \(O(n\log n)\)。

#include<bits/stdc++.h>
#define int long long
#define ull unsigned int
using namespace std;
const ull q=1145141;
const int N=4e5+5,p=1e9+7;
const double pi=acos(-1);
namespace FFT{
    int rev[N],mx,k;
    struct comn{double a,b;};
    struct dft{comn fg[N];};
    comn operator+(comn &x,comn &y){
        return {x.a+y.a,x.b+y.b};
    }comn operator-(comn &x,comn &y){
        return {x.a-y.a,x.b-y.b};
    }comn operator*(comn &x,comn &y){
        return {x.a*y.a-x.b*y.b,x.a*y.b+x.b*y.a};
    }void operator+=(comn &x,comn &y){x=x+y;}
    void operator-=(comn &x,comn &y){x=x-y;}
    void operator*=(comn &x,comn &y){x=x*y;}
    void operator+=(dft &x,dft &y){
        for(int i=0;i<mx;i++) x.fg[i]+=y.fg[i];
    }void operator-=(dft &x,dft &y){
        for(int i=0;i<mx;i++) x.fg[i]-=y.fg[i];
    }void init(int n){
        mx=1,k=0,rev[0]=0;
        while(mx<=n) mx*=2,k++;
        for(int i=0;i<mx;i++)
            rev[i]=(rev[i>>1]>>1)|((i&1)<<(k-1));
    }void fft(dft &a,int fl){
        for(int i=0;i<mx;i++)
            if(i<rev[i]) swap(a.fg[i],a.fg[rev[i]]);
        comn o={cos(pi),fl*sin(pi)},w={1,0};
        for(int i=1;i<mx;i*=2,o={cos(pi/i),fl*sin(pi/i)})
            for(int j=0;j<mx;j+=i*2,w={1,0})
                for(int l=j;l<j+i;l++){
                    comn x=a.fg[l],y=w*a.fg[l+i];
                    a.fg[l]+=y,a.fg[l+i]=x-y,w*=o;
                }
    }
}using namespace FFT;
int n,ans;string s;dft t[2];
ull hsh1[N],hsh2[N],qp[N];
int qpow(int x,int y){
    int re=1;
    while(y){
        if(y&1) re=re*x%p;
        x=x*x%p,y>>=1;
    }return re;
}ull hs1(int l,int r){
    return hsh1[l]-hsh1[r]*qp[l-r];
}ull hs2(int l,int r){
    return hsh2[l]-hsh2[r]*qp[r-l];
}signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>s,n=s.size(),qp[0]=1;
    s=" "+s,init(2*n);
    for(int i=1;i<=n;i++){
        t[s[i]-'a'].fg[i].a++,qp[i]=qp[i-1]*q;
        hsh1[i]=hsh1[i-1]*q+s[i]-'a';
    }for(int i=n;i;i--)
        hsh2[i]=hsh2[i+1]*q+s[i]-'a';
    fft(t[0],1),fft(t[1],1);
    for(int i=0;i<mx;i++){
        t[0].fg[i]*=t[0].fg[i];
        t[1].fg[i]*=t[1].fg[i];
    }fft(t[0],-1),fft(t[1],-1);
    for(int i=2;i<=2*n;i++){
        int sum=((t[0].fg[i].a+t[1].fg[i].a)/mx+0.5);
        ans+=qpow(2,sum/2-(i&1)+1)-1;
    }for(int i=1;i<=n;i++){
        int l=1,sum=0;
        int r=min(i,n-i+1);
        while(l<=r){
            int mid=(l+r)/2;
            if(hs1(i,i-mid)==hs2(i,i+mid))
                l=mid+1,sum=mid;else r=mid-1;
        }ans-=sum;
    }for(int i=1;i<n;i++){
        int l=1,sum=0;
        int r=min(i,n-i);
        while(l<=r){
            int mid=(l+r)/2;
            if(hs1(i,i-mid)==hs2(i+1,i+mid+1))
                l=mid+1,sum=mid;else r=mid-1;
        }ans-=sum;
    }cout<<(ans%p+p)%p;
    return 0;
}

标签:BZOJ3160,return,int,题解,void,万径,ull,comn,operator
From: https://www.cnblogs.com/chang-an-22-lyh/p/18680706/bzoj3160-wan_jing_ren_zong_mie-tj

相关文章

  • PKUWC 2025 题解
    本人太菜,实在不会T3,所以只有T1,T2的题解。注:考场上只做出来了Day1T1,其他题参考了其他人的题解。Day1T1电池检测题面有\(a\)个有电的电池和\(b\)个没电的电池,每次只能选择两个电池放进手电筒,只有这两个电池全有电才能让手电筒启动。问最坏情况下最少可以让手电筒启......
  • AT_abc389_f [ABC389F] Rated Range 题解
    题目传送门前置知识Treap|线段树解法考虑将询问的\(x\)离线下来在升序排序后一起处理。观察到每次操作只有\(+1\),即其之间的相对大小关系不会发生变化,此时就只需要支持将值在\([l,r]\)内的数加一,可以记录懒惰标记。线段树上二分找到端点或直接FHQ-Treap分裂出合法......
  • [ABC389C] Snake Queue题解
    前情题意:问题陈述有一个(蛇)队列。最初,队列是空的。你会得到\(Q\)个查询,这些查询应按给出的顺序处理。查询有三种类型:类型\(1\):以1l的形式给出。一条长度为\(l\)的蛇会被添加到队列的末尾。如果添加前队列为空,则新添加的蛇的头部位置为\(0\);否则,它就是队列中最后......
  • Atcoder ABC389E Square Price 题解 [ 绿 ] [ 二分 ] [ 贪心 ]
    SquarePrice:垃圾卡精度,垃圾卡精度,垃圾卡精度,傻逼出题人,傻逼出题人,傻逼出题人,傻逼出题人,傻逼出题人,傻逼出题人,傻逼出题人。把ll改__int128前WA*22,改__int128直接AC了,难评。抛开卡精度这题还是挺好的。暴力先考虑暴力思路,显然暴力应该这么打:把所有物品全丢进优先队列......
  • 【鱼皮大佬API开放平台项目】Spring Cloud Gateway HTTPS 配置问题解决方案总结
    问题背景项目架构为前后端分离的微服务架构:前端部署在8000端口API网关部署在9000端口后端服务包括:api-backend(9001端口)api-interface(9002端口)初始状态:前端已配置HTTPS(端口8000)后端服务未配置HTTPS通过Nginx进行反向代理遇到的问题第一阶段:400Ba......
  • uniapp获取元素高度不准确问题解决
    uniapp通过boundingClientRect获取的元素高度和实际高度差了不少,下面是复现和解决过程:我的代码: 得到的结果: 高度只有105用工具量一下: 实际有240px,遂gpt问下: 注意到了缩放比这个之前没想到的点,往下面看gpt更多的回复内容: 先获取系统缩放比,再乘以拿到的......
  • [BZOJ3451] Normal 题解
    这题分三步:葺网(期望)、淀粉质(点分治)、蓉翅(容斥),再佐以芬芳团(FFT),一道巨难无比的luogu黑题就诞生了。期望先考虑在淀粉树上,\(i\)点在\(j\)点的子树里的概率。实际上这个问题的每种情况相当于是\(n\)个点的各种排列方式。这也就相当于,我们在选择\(j\)点之前,没有选择路径\((......
  • PKUWC 2025 题解
    本人太菜,实在不会T3,所以只有T1,T2的题解。注:考场上只做出来了Day1T1,其他题参考了其他人的题解。Day1T1题面有\(a\)个有电的电池和\(b\)个没电的电池,每次只能选择两个电池放进手电筒,只有这两个电池全有电才能让手电筒启动。问最坏情况下最少可以让手电筒启动的尝试次......
  • THUWC2025题解
    Day1T1构造一个排列,使满足最多的形如\([l,r]\)内单调递增/减。一个简单的线段树优化DP,设状态\(f_{i,0/1}\)即可转移,\(O(n\logn)\)。T2支持往集合中加三维带权点,查询集合中没有任何一维与给出点对应维度相等的最大点权。唐题。一种暴力的想法是三维数点之类的,不太能......
  • PKUWC2025部分题解
    Day1A注意到,原题等价于构造一个\(a+b\)个点的完全图,使最大独立集\(<a\),且边数最小。很难发现,图必然被划分成\(a-1\)个完全图。据此DP或令\(a-1\)个图点数平均。CDAG上考虑暴力。设\(f_{u,i}\)表示第\(i\)轮在\(u\)是否先手必胜。转移枚举相邻点就好,\(\large......