zoukankan      html  css  js  c++  java
  • P3604 美好的每一天

    lxl 的题还真是毒瘤…

    题意大概是 l ~ r 区间有多少个回文子串…
    然后考虑怎么做…数字的出现次数怎么看都是和莫队没有关系的。
    不难想到,想要一段区间回文,必须小于等于一个有奇数次出现的字母。

    那么考虑 -> 这题

    你就有想法了,就是把一个区间异或起来。剩下的值就是奇数次出现的。

    那么又可以想到 一共有 26 个字母 你可以把每个字母压成 (2^0) ~ (2^{25})

    这样就可以当做数值来做了。

    问题1:怎么求区间异或和( O(1) 的 复杂度 )

    问题2: 怎么莫队(区间的当然和平常的莫队不太一样)

    请读者 仔细思考以上问题再继续下翻。

    异或和是可以通过像前缀和的方式求的
    前缀和的预处理 (sum_i) = (sum_{i-1}) + (a_i)
    查询 (sum_{i=l}^{r}) (sum_r) - (sum_{l-1})

    异或前缀和也是可以做的 类似正常的前缀和
    (sum_i) = (sum_{i-1}) ^ (a_i)
    (oplus_{i=l}^{r}) = (sum_r) ^ (sum_{l-1})

    然后考虑怎么莫队
    当你把 (sum_i) 设成了 1 到 i 的 异或和
    你需要做的就是求这个区间的两个数的异或和是否由二进制位组成。
    然后这个问题就转化成 (mathfrak{0(26n)}) 的预处理了
    你只需要算出来对它有贡献的且序列里有的然后放到 (vector)
    每次移动左右指针的时候修改的复杂度就会降低
    我个人建议把 所有的 l 都 减 1 这样操作起来会方便点 而且 r 到 r 这个区间也算贡献的。

    给出两道弱化版的题 建议做好了再做这题。

    https://www.luogu.org/problem/P4462
    https://www.luogu.org/problem/CF617E
    

    我在这道题上栽了个坑… 其他题我也没注意到这个问题 Ins 和 Del 操作建议放在一起
    不放在一起就会相互影响 这样答案可能不对
    这题的整体复杂度是 (mathfrak{0(26 nsqrt{n})})

    code

    #pragma GCC optimize("Ofast")
    #pragma GCC optimize(3)
    #include<bits/stdc++.h>
    using namespace std ;
    const int N = 6e4 + 5 ;
    struct node {
    	int l , r , id , bl ;
    	bool operator < (const node & c) const {
    		return bl < c.bl || (bl == c.bl && r < c.r) ;
    	}
    } q[N] ;
    int n , m , a[N] , Ans[N] , ans = 0 ;
    char s[N] ;
    vector < int > v[N] ;
    unsigned short cnt[1 << 26] ;
    bool vis[1 << 26] ;
    inline void Ins(int x) { ans += cnt[a[x]] ++ ; for( int & pt : v[x] ) ans += cnt[pt] ; }
    inline void Del(int x) { ans -= -- cnt[a[x]] ; for( int & pt : v[x] ) ans -= cnt[pt] ; }
    signed main() {
    	scanf("%d %d %s" , & n , & m , s + 1) ;
    	int unt = n / sqrt(m * 0.9) ;
    	for(register int i = 0 ; i <= n ; i ++) a[i] = i ? a[i - 1] ^ (1 << (s[i] - 'a')) : 0 , vis[a[i]] = 1 ;
    	for(register int i = 0 ; i <= n ; i ++)
    		for(register int j = 0 ; j <= 25 ; j ++) if(vis[a[i] ^ (1 << j)]) v[i].emplace_back(a[i] ^ (1 << j)) ;
    	for(register int i = 1 ; i <= m ; i ++) scanf("%d %d" , & q[i].l , & q[i].r) , q[i].bl = q[i].l / unt , q[i].id = i ;
    	sort(q + 1 , q + m + 1) ;
    	int l = q[1].l , r = q[1].l - 1; cnt[a[l - 1]] ++ ;
    	for(register int i = 1; i <= m; i ++) {
    			while(l > q[i].l) Ins(-- l - 1) ;
    			while(r < q[i].r) Ins(++ r) ;
    			while(l < q[i].l) Del(l ++ - 1) ;
    			while(r > q[i].r) Del(r --) ;
    			Ans[q[i].id] = ans ;
    	}
    	for(register int i = 1 ; i <= m ; i ++) printf("%d
    " , Ans[i]) ;
    	return 0 ;
    }
    
  • 相关阅读:
    百科知识 scm文件如何打开
    百科知识 STEP文件如何打开
    百科知识 tar文件如何打开
    百科知识 kux文件如何打开
    app开发中如何利用sessionId来实现服务端与客户端保持回话
    什么是云虚拟主机以及和云服务器之间的区别
    2016年百度百科怎么创建词条(高级技巧篇)
    使用Jsoup获取网页内容超时设置
    如何让自己在天猫开通的商铺能够在百度中输入关键词就能够搜索到
    百度百科词条义项排名靠前秘诀
  • 原文地址:https://www.cnblogs.com/Isaunoya/p/11642428.html
Copyright © 2011-2022 走看看