Hdu 5785 Interesting(给你一个字符串,你可以选择这个字符串的一个子串,记为s[l...r] 你可以选择一个k(i<=k< j)将这个子串划分成两半,如果这两半都是回文串,那么答案)
2016-08-02 19:54
399 查看
传送门:Hdu 5785 Interesting
给你一个字符串,你可以选择这个字符串的一个子串,记为s[l…r]
你可以选择一个k(i<=k< j)将这个子串划分成两半,如果这两半都是回文串,那么答案加上l*r,
同一个子串可以被划分多次,问最后的答案为多少。
思路:首先我们先对原来的子串进行一次manacher,那么假设以i这个点为分割点
分成s[l…i]和s[i+1…r],那么这个对答案的贡献便为(x1+x2+…+xn)*(y1+y2+…+ym)
x1,x2…xn表示和i点为终点构成回文串的起点,y1,y2,…ym表示和j点为起点构成回文串的终点
接下来的工作便是统计x1+…+xn和y1+…+yn
manacher中的p[i]表示以i为中心的(包含i这个字符的回文串半径长)
num1的前缀和表示以这个点为结尾的回文串的总个数,cnt1[i]表示到每个位置为中心的位置的总和(用double表示)
那么x[i]等于2*cnt1[i]-i*num1[i]
对于i为偶数的那些位置,num1[i/2]++,num1[i/2+p[i]/4+1]–;(对应回原来的字符串中),
同时记录一下cnt1[i/2]+=i/2,cnt1[i/2+p[i]/4+1]-=i/2;(表示到每个位置为中心的位置的总和)
对于i为奇数的那些位置,num1[i/2+1]++,num1[i/2+p[i]/4+1]–;
同时记录一下,cnt1[i/2+1]+=1.0*i/2,cnt1[i/2+p[i]/4+1]-=1.0*i/2
num2前缀和表示以这个点为开头的回文串的总个数,cnt2[i]表示到每个位置为中心的位置的总和(用double表示)
那么y[i]等于2*cnt2[i]-i*num2[i]
对于i为偶数的那些位置,num2[i/2+1]–,num2[i/2-p[i]/4]++;(对应回原来的字符串中),
同时记录一下cnt2[i/2-p[i]/4]+=1.0*i/2,cnt2[i/2+1]-=1.0*i/2
对于i为奇数的那些位置,num2[i/2+1]–,num2[(i+1)/2-p[i]/4]++;
同时记录一下cnt2[(i+1)/2-p[i]/4]+=1.0*i/2,cnt2[i/2+1]-=1.0*i/2
又因为cnt最终都是要乘以2的,所以刚开始的除以2就不要了
给你一个字符串,你可以选择这个字符串的一个子串,记为s[l…r]
你可以选择一个k(i<=k< j)将这个子串划分成两半,如果这两半都是回文串,那么答案加上l*r,
同一个子串可以被划分多次,问最后的答案为多少。
思路:首先我们先对原来的子串进行一次manacher,那么假设以i这个点为分割点
分成s[l…i]和s[i+1…r],那么这个对答案的贡献便为(x1+x2+…+xn)*(y1+y2+…+ym)
x1,x2…xn表示和i点为终点构成回文串的起点,y1,y2,…ym表示和j点为起点构成回文串的终点
接下来的工作便是统计x1+…+xn和y1+…+yn
manacher中的p[i]表示以i为中心的(包含i这个字符的回文串半径长)
num1的前缀和表示以这个点为结尾的回文串的总个数,cnt1[i]表示到每个位置为中心的位置的总和(用double表示)
那么x[i]等于2*cnt1[i]-i*num1[i]
对于i为偶数的那些位置,num1[i/2]++,num1[i/2+p[i]/4+1]–;(对应回原来的字符串中),
同时记录一下cnt1[i/2]+=i/2,cnt1[i/2+p[i]/4+1]-=i/2;(表示到每个位置为中心的位置的总和)
对于i为奇数的那些位置,num1[i/2+1]++,num1[i/2+p[i]/4+1]–;
同时记录一下,cnt1[i/2+1]+=1.0*i/2,cnt1[i/2+p[i]/4+1]-=1.0*i/2
num2前缀和表示以这个点为开头的回文串的总个数,cnt2[i]表示到每个位置为中心的位置的总和(用double表示)
那么y[i]等于2*cnt2[i]-i*num2[i]
对于i为偶数的那些位置,num2[i/2+1]–,num2[i/2-p[i]/4]++;(对应回原来的字符串中),
同时记录一下cnt2[i/2-p[i]/4]+=1.0*i/2,cnt2[i/2+1]-=1.0*i/2
对于i为奇数的那些位置,num2[i/2+1]–,num2[(i+1)/2-p[i]/4]++;
同时记录一下cnt2[(i+1)/2-p[i]/4]+=1.0*i/2,cnt2[i/2+1]-=1.0*i/2
又因为cnt最终都是要乘以2的,所以刚开始的除以2就不要了
#include<bits/stdc++.h> using namespace std; const int maxn=2001000; const int MOD=1000000007; char s[maxn],str[maxn]; int p[maxn]; long long num1[maxn],num2[maxn]; long long cnt1[maxn],cnt2[maxn]; int main(){ while(scanf("%s",str+1)!=EOF){ int len=strlen(str+1); for(int i=1;i<=len+1;i++) s[i*2]=str[i],s[i*2-1]='#'; s[0]='*'; int id=0,maxv=0; memset(cnt1,0,sizeof(cnt1)); memset(cnt2,0,sizeof(cnt2)); memset(num1,0,sizeof(num1)); memset(num2,0,sizeof(num2)); memset(p,0,sizeof(p)); for(int i=1;i<=len*2;i++){ if(p[id]+id>i) p[i]=min(p[2*id-i],p[id]+id-i); else p[i]=1; while(s[i-p[i]]==s[i+p[i]]) ++p[i]; if(i+p[i]>id+p[id]) id=i; } long long ans=0; for(int i=1;i<=len*2;i++){ p[i]=p[i]*2-1; if(i&1){ num1[i/2+1]++,num1[i/2+p[i]/4+1]--; cnt1[i/2+1]+=i,cnt1[i/2+p[i]/4+1]-=i; num2[i/2+1]--,num2[(i+1)/2-p[i]/4]++; cnt2[(i+1)/2-p[i]/4]+=i,cnt2[i/2+1]-=i; } else{ num1[i/2]++,num1[i/2+p[i]/4+1]--; cnt1[i/2]+=i,cnt1[i/2+p[i]/4+1]-=i; num2[i/2+1]--,num2[i/2-p[i]/4]++; cnt2[i/2-p[i]/4]+=i,cnt2[i/2+1]-=i; } } for(int i=1;i<=len;i++) cnt1[i]+=cnt1[i-1],num1[i]+=num1[i-1],cnt2[i]+=cnt2[i-1],num2[i]+=num2[i-1]; for(int i=1;i<len;i++) ans=(ans+( (cnt1[i]-num1[i]*i)%MOD*( (cnt2[i+1]-num2[i+1]*(i+1)) %MOD))%MOD)%MOD; printf("%lld\n",ans); } return 0; }
相关文章推荐
- 回文串是指这个字符串无论从左读还是从右读,所读的顺序是一样的;简而言之,回文串是左右对称的。现在,对于一个给定的母串 abcdedcb求最长回文子串的长度
- 2017-5-14 湘潭市赛 Partial Sum 给n个数,每次操作选择一个L,一个R,表示区间左右端点,该操作产生的贡献为[L+1,R]的和的绝对值-C。 0<=L<R<=n; 如果选过L,R这两个位置,那么以后选择的L,R都不可以再选择这两个位置。最多操作m次,求可以获得的 最大贡献和。
- uva 11584 题目大意: 给一个字符串, 要求把它分割成若干个子串,使得每个子串都是回文串。问最少可以分割成多少个。
- [转]给你一个单词a,如果通过交换单词中字母的顺序可以得到另外的单词b,那么定义b是a的兄弟单词。现在给你一个字典,用户输入一个单词,让你根据字典找出这个单词有多少个兄弟单词
- 给你一个单词a,如果通过交换单词中字母的顺序可以得到另外的单词b,那么定义b是a的兄弟单词。现在给你一个字典,用户输入一个单词,让你根据字典找出这个单词有多少个兄弟单词。
- C 这个字符串参数必须包含一个或者多个数字,函数应该把这些数字字符转换为整数并返回这个整数。如果字符串参数包含了任何非数字字符,函数就返回零。
- 请一个在字符串中找出连续最长的数字串,并把这个串的长度返回;如果存在长度相同的连续数字串,返回最后一个连续数字串
- hdu 3622 Bomb Game 2-SAT+二分答案 有N对点,求最大的半径R,使从每对点中选择一个点,且这N个点以自己为圆心,半径为R的圆两两不相交.(最大半径在所有半径相同情况下)
- 字符串包含一个或多个数字,编写函数把数字字符转化为整数并返回这个整数。如果字符串包含任何非数字字符,函数就返回零。
- 为下面的函数原型编写函数定义: int ascii_to_integer(char *str); 这个字符串参数必须包含一个或者多个数字,函数应该把这些数字字符转换为整数并返回这个整数。如果字符串参数
- 这个字符串参数必须包含一个或多个数字,函数应该把这些 数字字符转换为整数并返回这个整数。如果字符串参数包含 了任何非数字字符,函数就返回零。
- HDU 1503 Advanced Fruits 由两个字符串组成一个最短新串 (最长公共子串变形)
- 根据C++标准,如果const的引用被初始化为对一个临时变量的引用,那么它会使这个临时变量的生命期变得和它自己一样
- 4.4将一个字符串中的n个字符复制到另一个字符串中,如果n大于这个字符串的长度,则超出部分以NUL补充
- 二分图性质 一个图如果是二分图,那么这个图不存在奇环,反之也成立
- 用三重循环求一个字符串的最大回文串(连续重复出现的最长子串)
- C++_USACO_求一个字符串的从开头字母开始,直到发现某一不相同字母时,这个子串的长度
- 输入一个字符串,如果第一个字符是大写并且其他字符不是大写,那么输出true,否则输出false。
- 如果字符串的一个子串(其长度大于 1)的各个字符均相同,则称之为等值子串。试设计一算法,求出串S中的最大等值子串 函数返回最大等值子串的长度,如果没有则返回1。 例如: 若S= “abc123abc1
- 字符串参数必须包含一个或者多个数字,函数应该把这些数字字符转换为整数并返回这个整数。如果字符串参数包含了任何非数字字符,函数就返回零