Palindromic Subsets 数学 + 线段树
https://www.hackerrank.com/contests/101hack44/challenges/palindromic-subsets
如果有3个a。2个b。1个c。
每个a看成不同的,那么能选出多少个不同的回文串呢?
从回文串入手,因为回文串最多只有1种字母是奇数个。
那么,如果我能快速算区间[L, R]中各种字母出现的次数,就好了。
假设上面的数据,所得到的回文串是:
a取奇数个:2^2 * 2^1(b只能取偶数个) * 2^0(C是偶数个,这个时候是空集)
然后再枚举b取奇数个,其他取偶数个。
最后,还有一种情况,就是全部都是偶数个,这个时候因为可能选到的全部都是空集,所以最后结果要减去1.
接下来就是快速计算了。明显线段树,一开始不知道怎么维护区间,
其实区间更新,很简单,因为字母的数量是不会变的,对于区间存在2个a的话,反转1次,就只是2个b。
所以只需要枚举26个字母,cnt[(i + k) % 26] = cnt[i]
意思是产生这个字母的个数是有它来产生的。然后线段树更新即可。
线段树写了很多次,看模板才想起怎么lazy--update 苦逼。
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <assert.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL; #include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
#define root 1, n, 1
#define lson L, mid, cur << 1
#define rson mid + 1, R, cur << 1 | 1 const int maxn = 1e5 + ;
char str[maxn];
const int MOD = 1e9 + ;
char to[];
int add[maxn << ];
LL quick_pow(LL a, LL b, int MOD) {
LL ans = ;
assert(b >= );
while (b) {
if (b & ) {
ans = ans * a;
if (ans >= MOD) ans %= MOD;
}
b >>= ;
a *= a;
if (a >= MOD) a %= MOD;
}
return ans;
}
struct node {
int cnt[ + ];
} seg[maxn << ];
void toget(struct node &a, int val) {
int cnt[ + ] = {};
for (int i = ; i < ; ++i) {
cnt[i] = a.cnt[i];
}
for (int i = ; i < ; ++i) {
a.cnt[(i + val) % ] = cnt[i];
}
return;
}
void pushUp(int cur) {
for (int i = ; i < ; ++i) {
seg[cur].cnt[i] = seg[cur << ].cnt[i] + seg[cur << | ].cnt[i];
}
}
void pushDown(int cur) {
if (add[cur]) {
add[cur << | ] += add[cur];
add[cur << | ] %= ;
add[cur << ] += add[cur];
add[cur << ] %= ;
toget(seg[cur << ], add[cur]);
toget(seg[cur << | ], add[cur]);
add[cur] = ;
}
}
void build(int L, int R, int cur) {
if (L == R) {
seg[cur].cnt[str[L] - 'a'] = ;
return;
}
int mid = (L + R) >> ;
build(lson);
build(rson);
pushUp(cur);
}
void upDate(int be, int en, int val, int L, int R, int cur) {
if (L >= be && R <= en) {
toget(seg[cur], val);
add[cur] += val;
add[cur] %= ;
return;
}
pushDown(cur);
int mid = (L + R) >> ;
if (mid >= be) upDate(be, en, val, lson);
if (mid < en) upDate(be, en, val, rson);
pushUp(cur);
}
int query(int be, int en, int ch, int L, int R, int cur) {
if (L >= be && R <= en) {
return seg[cur].cnt[ch];
}
pushDown(cur);
int mid = (L + R) >> ;
int lans = , rans = ;
if (mid >= be) lans = query(be, en, ch, lson);
if (mid < en) rans = query(be, en, ch, rson);
return lans + rans;
}
void work() {
for (int i = 'a'; i <= 'z' - ; ++i) {
to[i] = i + ;
}
to['z'] = 'a';
int n, q;
scanf("%d%d", &n, &q);
scanf("%s", str + );
build(root);
while (q--) {
int flag, L, R;
scanf("%d", &flag);
if (flag == ) {
scanf("%d%d", &L, &R);
L++;
R++;
LL ans = ;
int len = ;
for (int i = ; i < ; ++i) {
int ret = query(L, R, i, root);
if (ret > ) len++;
else continue;
ans = ans * quick_pow(, ret - , MOD);
if (ans >= MOD) ans %= MOD;
}
ans *= (len + );
ans %= MOD;
ans = (ans - + MOD) % MOD;
cout << ans << endl;
} else {
int t;
scanf("%d%d%d", &L, &R, &t);
L++;
R++;
upDate(L, R, t % , root);
// printf("%d****\n", query(3, 3, 'u' - 'a', root));
}
}
// cout << query(1, n, 'o' - 'a', root) << endl;
} int main() {
#ifdef local
freopen("data.txt", "r", stdin);
// freopen("data.txt", "w", stdout);
#endif
work();
return ;
}
Palindromic Subsets 数学 + 线段树的更多相关文章
- Codeforces 311D Interval Cubing 数学 + 线段树 (看题解)
Interval Cubing 这种数学题谁顶得住啊. 因为 (3 ^ 48) % (mod - 1)为 1 , 所以48个一个循环节, 用线段树直接维护. #include<bits/stdc ...
- 2017ICPC北京赛区网络赛 Minimum(数学+线段树)
描述 You are given a list of integers a0, a1, …, a2^k-1. You need to support two types of queries: 1. ...
- [CSP-S模拟测试]:最大值(数学+线段树)
题目背景 $Maxtir$最喜欢最大值. 题目传送门(内部题128) 输入格式 第$1$行输入四个正整数$n,m,q$. 第$2$至$n+1$行中,第$i+1$行输入魔法晶石$i$的三种属性$(x_i ...
- [CSP-S模拟测试]:旅行(数学+线段树)
题目传送门(内部题12) 输入格式 第一行,一个整数$n$,代表树的点数.第二行,$n$个整数,第$i$个整数是$B_i$,描述排列$B$.接下来$n−1$行,每行两个整数$u,v$,描述一条树边$( ...
- Sasha and a Very Easy Test CodeForces - 1109E (数学,线段树)
大意: 给定n元素序列, q个操作: (1)区间乘 (2)单点除(保证整除) (3)区间求和对m取模 要求回答所有操作(3)的结果 主要是除法难办, 假设单点除$x$, $x$中与$m$互素的素因子可 ...
- BZOJ 5334--[Tjoi2018]数学计算(线段树)
5334: [Tjoi2018]数学计算 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 220 Solved: 147[Submit][Status ...
- 【BZOJ5334】数学计算(线段树)
[BZOJ5334]数学计算(线段树) 题面 BZOJ 洛谷 题解 简单的线段树模板题??? 咕咕咕. #include<iostream> #include<cstdio> ...
- codeforces 446C DZY Loves Fibonacci Numbers(数学 or 数论+线段树)(两种方法)
In mathematical terms, the sequence Fn of Fibonacci numbers is defined by the recurrence relation F1 ...
- 【线段树/数学/扩展欧几里得】 Bzoj 3913:奇数国
Description 在一片美丽的大陆上有100000个国家,记为1到100000.这里经济发达,有数不尽的账房,并且每个国家有一个银行.某大公司的领袖在这100000个银行开户时都存了3大洋,他惜 ...
随机推荐
- Android中个人推崇的数据库使用方式
手机应用开发中常常会使用到数据库存储一些资料或者进行数据缓存,android中为我们提供了一个轻量的数据库.在上层进行了一层封装,同一时候还为我们提供了ContentProvider的框架.方便我们进 ...
- CRF图像切割简单介绍
这里主要是讲Conditional Random Fields(CRF)用于pixel-wise的图像标记(事实上就是图像切割).CRF经经常使用于 pixel-wise的label 预測.当把像素的 ...
- Xsolla和Hi-Rez工作室联手推行SMITE
视频游戏店面管理和计费解决方式的领导者,Xsolla.将重拳出击将与Hi-Rez游戏工作室合作.该工作室是一家美国的独立游戏开发商,主要开发MOBA游戏-SMITE. 支持全球600多种支付方式 Xs ...
- vue入门教程 (vueJS2.X)
vue入门教程vueJS2.X 写在前面 看完此教程可以达到:能看懂并能修改简单的vue项目. 看的过程中,请把所有例子都放到html文件中跑一遍. Vue.js 是什么 Vue.js(读音 /vju ...
- 发布Java桌面程序
我拿了一份桌面工具的开源代码,修修改改,在elipse上运行,感觉良好,但到了发布应用程序,就傻眼了.我居然不知道咋发布! 呵呵,不愧是Java小白! 如果是微软阵营,直接就编译成exe了.但java ...
- Linux常用服务安装部署
1,centos7默认是装有python的,检查python版本的命令 # 检查python版本 : python -V 2,centOS在安装python3以及tab补全功能 下载python3源码 ...
- 设计模式-(7)桥接(swift版)
一,概念 桥接模式为把抽象层次结构从实现中分离出来,使其可以独立变更,抽象层定义了供客户端使用的上层抽象接口,实现层次结构定义了供抽象层次使用的底层接口,实现类的引用被封装于抽象层的实例中,桥接就形成 ...
- C语言预处理命令总结大全 :宏定义
C程序的源代码中可包括各种编译指令,这些指令称为预处理命令.虽然它们实际上不是C语言的一部分,但却扩展了C程序设计的环境.本节将介绍如何应用预处理程序和注释简化程序开发过程,并提高程序的可读性.ANS ...
- 2018OKR年中回顾 转
一.2018OKR规划 目标1.温习专业基础知识 关键结果1.1 阅读<微积分之屠龙宝刀>+<微积分之倚天宝剑>,加深理解高等数学微积分的各种概念与公式(0.2 屠龙宝刀看了三 ...
- bzoj 1127 KUP —— 最大子矩形+答案构造
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1127 首先,把权值 > 2*k 的点作为“坏点”,然后在图中用悬线法找权值最大的子矩形 ...