template<class T> inline void rd(T &x)
{
x=0;char o,f=1;
while(o=getchar(),o<48)if(o==45)f=-f;
do x=(x<<3)+(x<<1)+(o^48);
while(o=getchar(),o>47);
x*=f;
}
数论
快速幂
typedef long long ll;
ll quickpow(ll a,ll n,ll p) //a^n%p;
{
ll ans = 1;
while(n)
{
if(n&1) ans = ans * a % p;
a = a * a %p;
n >>= 1;
}
return ans;
}
欧几里得
int gcd(int a,int b)
{
if(b==0)return a;
return gcd(b,a%b);
}
int lcm(int a,int b)
{
return a/gcd(a,b)*b;
}
扩展欧几里得
(1)求解不定方程;
(2)求解模线性方程(线性同余方程);
(3)求解模的逆元;
int exgcd(int a,int b,int &x,int &y)
{
if(b==0) {
x = 1;
y = 0;
return a;
}
int r = exgcd(b,a%b,x,y);
int t = x;
x = y;
y = t-a/b*y;
return r;
}
最小生成树
·prim
const int maxn = 505;
const int INF = 0x3f3f3f3f;
bool vis[maxn];
int lowc[maxn];
int cost[maxn][maxn];
int prim()
{
int asn = 0;
memset(vis,false,sizeof(vis));
vis[0] = true;
for(int i = 1;i < n;i++) lowc[i] = cost[0][i];
for(int i = 1;i < n;i++)
{
int minc = INF;
int p = -1;
for(int j = 0;j < n;j++)
if(!vis[j]&&minc > low[j])
{
minc = lowc[j];
p = j;
}
if(minc == INF) return -1;
ans+=minc;
for(int j = 0;j < n;j++)
if(!vis[j]&&lowc[j]>cost[p][j])
lowc[j] = cost[p][j];
}
return ans;
}
最短路径
· 单源最短路径 迪杰斯特拉 Dijkstra
堆优化
const int maxn = 505;
vector<pair<int,int> > E[maxn];
priority_queue<pair<int,int> > q;
int pre[maxn];
bool vis[maxn];
int dis[maxn];
int s,d;//s为开始节点.
void dijkstar()
{
dis[s] = 0;
q.push(make_pair(-dis[s],s));
while(!q.empty())
{
int t = q.top().second;
q.pop();
if(vis[t])
continue;
vis[t] = true;
for(int i = 0;i < E[t].size();i++)
{
int to = E[t][i].first;
int di = E[t][i].second;
if(dis[to] > dis[t]+di)
{
dis[to] = dis[t]+di;
pre[to] = t;
q.push(make_pair(-dis[to],to);
}
}
}
}
强连通分量
·Tarjan
const int maxn = 5e5+5;
vector<int> ep[maxn];
vector<int> bel[maxn];
stack<int> s;
int cnt,cntb;
int dfn[maxn];
int low[maxn];
int belong[maxn];
int out[maxn];
bool in_stack[maxn];
void Tarjan(int u)
{
dfn[u] = low[u] = ++cnt;
s.push(u);
in_stack[u] = true;
for(int i = 0;i < ep[u].size();i++)
{
int v = ep[u][i];
if(!dfn[v])
{
Tarjan(v);
low[u] = min(low[u],low[v]);
}
else if(in_stack[v])
low[u] = min(low[u],dfn[v]);
}
if(dfn[u] == low[u])
{
++cntb;
int node;
do
{
node = s.top();
s.pop();
in_stack[node] = false;
belong[node] = cntb;
bel[cntb].push_back(node);
}while(node!=u);
}
}
·Kosaraju
·树状数组
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
int c[maxn];
int a[maxn];
int n;
int lowbit(int x)
{
return x&(-x);
}
void Update(int i,int k)//在i位置上的值加k
{
while(i<=n)
{
c[i]+=k,i+=lowbit(i);
}
}
int sum(int x)//求a[1...x]的和
{
int ret=0;
while(x)
{
ret+=c[x],x-=lowbit(x);
}
return ret;
}
int main()
{
cin >> n;
for(int i = 1;i <= n;i++)
{
cin >> a[i];
Update(i,a[i]);
}
cout << sum(n)<<endl;
return 0;
}
Manacher
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e3+5;
int p[maxn*2];
string Manacher(string s)
{
string t= "$#";
for(int i = 0;i < s.size();i++)
{
t+=s[i];
t+="#";
}
int mx = 0,id=0,reslen=0,rescenter=0;
for(int i =1;i < t.size();i++)
{
p[i]=mx>id?min(p[2*id-i],mx-i):1;
while(t[i+p[i]]==t[i-p[i]])p[i]++;
if(i+p[i]>mx)
{
mx=i+p[i];
id=i;
}
if(p[i]>reslen)
{
reslen=p[i];
rescenter=i;
}
}
return s.substr((rescenter-reslen)/2,reslen-1);
}
int main()
{
string s;
getline(cin,s);
string t = Manacher(s);
cout << t.size()<<endl;
return 0;
}
线段树
//#include <bits/stdc++.h>
//
//using namespace std;
//const int maxn = 1e5+5;
//typedef long long ll;
//typedef unsigned long long ull;
//struct node{
// ll sum,lazy;
//};
//int n,m;
//int a[maxn];
//node t[4*maxn];
//void change(int x,int tl,int tr,int p,int k)//单点修改p位置加k
//{
// if(tl==tr)
// {
// t[x].sum+=k;
// return;
// }
// int mid = (tl+tr)>>1;
// if(p<=mid)change(2*x,tl,mid,p,k);
// else change(2*x+1,mid+1,r,p,k);
// t[x].sum=t[2*x].sum+t[2*x+1].sum;
//}
//void update(int x,int tl,int tr)
//{
// t[x].sum = t[x].sum+(tr-tl+1)*t[x].lazy;
// if(tl!=tr)
// {
// t[2*x].lazy+=t[x].lazy;
// t[2*x+1].lazy+=t[x].lazy;
// }
// t[x].lazy=0;
//}
//void change(int x,int tl,int tr,int l,int r,int k)
//{
// if(tl==l&&tr==r)
// {
// t[x].lazy+=k;
// return;
// }
// if(t[x].lazy)update(x,tl,tr);
// int mid = (tl+tr)>>1;
// if(r<=mid)change(2*x,tl,mid,l,r,k);
// else if(l>mid)change(2*x+1,mid+1,tr,l,r,k);
// else{
// change(2*x,tl,mid,l,mid,k);
// change(2*x+1,mid+1,tr,mid+1,r,k);
// }
// t[x].sum=t[2*x].sum+(mid-tl+1)*t[2*x].lazy+t[2*x+1].sum+(tr-mid)*t[2*x+1].lazy;
//}
//ll ask(int x,int tl,int tr,int l,int r)//查询[l,r]的和
//{
// if(tl==l&&tr==r) return t[x].sum;
// int mid = (tl+tr)>>1;
// if(r<=mid)return ask(2*x,tl,mid,l,r);
// else if(l>mid)return ask(2*x+1,mid+1,tr,l,r);
// else{
// return ask(2*x,tl,mid,l,mid)+ask(2*x+1,mid+1,tr,mid+1,r);
// }
//}
//void build(int x,int l,int r)
//{
// if(l==r)
// {
// t[x].sum=a[l];
// return ;
// }
// int mid = (l+r)>>1;
// build(2*x,l,mid);
// build(2*x+1,mid+1,r);
// t[x].sum = t[2*x].sum+t[2*x+1].sum;
//}
//int main()
//{
//
// return 0;
//}
#include <bits/stdc++.h>
using namespace std;
#define maxn 100007 //元素总个数
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
int Sum[maxn<<2],Add[maxn<<2];//Sum求和,Add为懒惰标记
int A[maxn],n;//存原数组数据下标[1,n]
//PushUp函数更新节点信息 ,这里是求和
void PushUp(int rt){Sum[rt]=Sum[rt<<1]+Sum[rt<<1|1];}
//Build函数建树
void Build(int l,int r,int rt){ //l,r表示当前节点区间,rt表示当前节点编号
if(l==r) {//若到达叶节点
Sum[rt]=A[l];//储存数组值
return;
}
int m=(l+r)>>1;
//左右递归
Build(l,m,rt<<1);
Build(m+1,r,rt<<1|1);
//更新信息
PushUp(rt);
}
void PushDown(int rt,int ln,int rn){
//ln,rn为左子树,右子树的数字数量。
if(Add[rt]){
cout << rt <<endl;
//下推标记
Add[rt<<1]+=Add[rt];
Add[rt<<1|1]+=Add[rt];
//修改子节点的Sum使之与对应的Add相对应
Sum[rt<<1]+=Add[rt]*ln;
Sum[rt<<1|1]+=Add[rt]*rn;
//清除本节点标记
Add[rt]=0;
}
}
void Update(int L,int C,int l,int r,int rt){//l,r表示当前节点区间,rt表示当前节点编号
if(l==r){//到叶节点,修改
Sum[rt]+=C;
return;
}
int m=(l+r)>>1;
//根据条件判断往左子树调用还是往右
if(L <= m) Update(L,C,l,m,rt<<1);
else Update(L,C,m+1,r,rt<<1|1);
PushUp(rt);//子节点更新了,所以本节点也需要更新信息
}
void Update(int L,int R,int C,int l,int r,int rt){//L,R表示操作区间,l,r表示当前节点区间,rt表示当前节点编号
cout << l <<' '<<r <<endl;
if(L <= l && r <= R){//如果本区间完全在操作区间[L,R]以内
Sum[rt]+=C*(r-l+1);//更新数字和,向上保持正确
Add[rt]+=C;//增加Add标记,表示本区间的Sum正确,子区间的Sum仍需要根据Add的值来调整
return ;
}
int m=(l+r)>>1;
PushDown(rt,m-l+1,r-m);//下推标记
//这里判断左右子树跟[L,R]有无交集,有交集才递归
if(L <= m) Update(L,R,C,l,m,rt<<1);
if(R > m) Update(L,R,C,m+1,r,rt<<1|1);
PushUp(rt);//更新本节点信息
}
int Query(int L,int R,int l,int r,int rt){//L,R表示操作区间,l,r表示当前节点区间,rt表示当前节点编号
if(L <= l && r <= R){
//在区间内,直接返回
return Sum[rt];
}
int m=(l+r)>>1;
//下推标记,否则Sum可能不正确
PushDown(rt,m-l+1,r-m);
//累计答案
int ANS=0;
if(L <= m) ANS+=Query(L,R,l,m,rt<<1);
if(R > m) ANS+=Query(L,R,m+1,r,rt<<1|1);
return ANS;
}
int main()
{
cin >> n;
for(int i =1;i <=n;i++)
cin >> A[i];
//建树
Build(1,n,1);
int ANS=Query(1,n,1,n,1);
cout << ANS <<endl;
//点修改
// Update(L,C,1,n,1);
//区间修改
Update(1,5,1,1,n,1);
//区间查询
ANS=Query(1,n,1,n,1);
cout << ANS<<endl;
return 0;
}
字符串哈希
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 2e5+5;
const int X=131;
ull pre[maxn],suf[maxn],p[maxn];
char s[maxn];
int n;
void Hash()
{
p[0]=1;
for(int i =1;i<=n;i++)
{
pre[i]=pre[i-1]*X+s[i]-'a'+1;
p[i]=p[i-1]*X;
}
for(int i = n;i>=1;i--)
{
suf[i]=suf[i+1]*X+s[i]-'a'+1;
}
}
ull getpre(int l,int r)
{
return pre[r]-pre[l-1]*p[r-l+1];
}
ull getsuf(int l,int r)
{
return suf[l]-suf[r+1]*p[r-l+1];
}
bool eql(int l1,int r1,int l2,int r2)
{
return getpre(l1,r1)==getpre(l2,r2);
}
bool huiwen(int r)
{
return getpre(1,r/2)==getsuf(ceil(r*1.0/2)+1,r);
}
bool check(int r)
{
if(r&1)
{
return huiwen((r+1)/2)&&eql(1,(r+1)/2,(r+1)/2,r);
}
return huiwen(r/2)&&eql(1,r/2,r/2+1,r);
}
int main()
{
cin >> s+1;
n=strlen(s+1);
Hash();
int ans=0;
for(int i = 1;i <= n;i++)
{
if(check(i))ans++;
}
printf("%d\n",ans);
return 0;
}