ACM模板(临时)
ver1.0,待更新
文章目录
一.数据结构
KMP
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+7;
int ne[N];
string s1,s2;
int len1 ,len2;
void init(){
int ix1 = 0,ix2= -1;
ne[0] = -1;
while(ix1<len1){
if(ix2==-1||s1[ix2]==s1[ix1]){
ne[++ix1]=++ix2;
}
else ix2 = ne[ix2];
}
}
void KMP(){
int ix1 = 0,ix2 =0;
while(ix1<len2){
if(ix2==-1||s2[ix1]==s1[ix2]) ix1++,ix2++;
else ix2 = ne[ix2];
if(ix2 == len1){
cout<< ix1-len1<<" " ;
}
}
}
int main(){
int n;
cin>>n>>s1>>n>>s2;
len1 = s1.length();
len2 = s2.length();
init();
KMP();
return 0;
}
Trie 树
const int N = 1e6+7;
int son[N][26],cnt[N],idx=0;
void insert(string str){
int p = 0;
for(int i = 0;str[i];i++){
int u = str[i] - 'a';
if(!son[p][u]) son[p][u] = ++idx;
p = son[p][u];
}
cnt[p]++;
}
int query(string str){
int p = 0;
for(int i = 0;str[i];i++){
int u = str[i] - 'a';
if(!son[p][u]) return 0;
p = son[p][u];
}
return cnt[p];
}
带权并查集
食物链
动物王国中有三类动物 A,B,C,A 吃 B,B 吃 C,C 吃 A。现有 N 个动物,以 1∼N 编号。
每个动物都是 A,B,C 中的一种,但是我们并不知道它到底是哪一种。
第一种说法是 1 X Y,表示 X 和 Y 是同类。
第二种说法是 2 X Y,表示 X 吃 Y。
此人对 N 个动物,用上述两种说法,一句接一句地说出 K 句话,这 K 句话有的是真的,有的是假的。
当一句话满足下列三条之一时,这句话就是假话,否则就是真话。
当前的话与前面的某些真的话冲突,就是假话;
当前的话中 X 或 Y 比 N 大,就是假话;
当前的话表示 X 吃 X,就是假话。
你的任务是根据给定的 N 和 K 句话,输出假话的总数。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+7;
int A[N],d[N];
int find(int x){
if(A[x]!=x) {
int t = find(A[x]);
d[x] += d[A[x]];
A[x] = t;
}
return A[x];
}
int main(){
int n,m;
cin>>n>>m;
for(int i = 1;i<=n;i++) A[i] = i;
int res = 0;
for(int i = 1;i<=m;i++){
int t,x,y;
cin>>t>>x>>y;
int px = find(x),py = find(y);
if(x>n||y>n) res++;
else {
if(t==1) {
if(px==py&&(d[x]-d[y])%3)res++;
else if(px!=py){
A[px] =py;
d[px] = d[y]-d[x];
}
}
else {
if(px==py&&(d[x]-d[y]-1)%3) res++;
else if(px!=py){
A[px] = py;
d[px] = d[y]-d[x]+1;
}
}
}
}
cout<<res<<endl;
return 0;
}
字符串哈希
841. 字符串哈希
给定一个长度为 n 的字符串,再给定 m 个询问,每个询问包含四个整数 l1,r1,l2,r2,请你判断 [l1,r1] 和 [l2,r2] 这两个区间所包含的字符串子串是否完全相同。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+7;
typedef unsigned long long ull;
const int I = 131;
ull p[N]={1},h[N],n,q;
char s[N];
ull check(int l,int r){
return h[r]-h[l-1]*p[r-l+1];
}
int main(){
scanf("%d%d%s",&n,&q,s+1);
for(int i = 1;i<=n;i++){
p[i] = p[i-1]*I;
h[i] = I*h[i-1] + s[i];
}
while(q--){
int l,r,ll,rr;
cin>>l>>r>>ll>>rr;
if(check(l,r)==check(ll,rr)) cout<<"Yes"<<endl;
else cout<<"No\n";
}
return 0;
}
线段树
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+7;
typedef long long ll;
ll A[N];
ll n,m,p;
struct TREE{
ll val,lazy=0,mul=1;
}tree[N*4];
void pushup(ll rt){
tree[rt].val = (tree[rt*2].val+tree[rt*2+1].val)%p;
}
void build(ll l,ll r,ll rt){
if(l==r) {
tree[rt].val = A[l];
return ;
}
ll mid = (l+r)/2;
build(l,mid,rt*2);build(mid+1,r,rt*2+1);
pushup(rt);
}
void pushdown(ll l,ll r,ll rt){
tree[rt*2].val = (tree[rt].mul*tree[rt*2].val+tree[rt].lazy*l)%p;
tree[rt*2+1].val = (tree[rt].mul*tree[rt*2+1].val+tree[rt].lazy*r)%p;
tree[rt*2].mul = (tree[rt].mul*tree[rt*2].mul)%p;
tree[rt*2+1].mul = (tree[rt].mul*tree[rt*2+1].mul)%p;
tree[rt*2].lazy = (tree[rt*2].lazy*tree[rt].mul+tree[rt].lazy)%p;
tree[rt*2+1].lazy = (tree[rt*2+1].lazy*tree[rt].mul+tree[rt].lazy)%p;
tree[rt].lazy = 0;
tree[rt].mul = 1;
}
void updata1(ll L,ll R,ll C,ll l,ll r,ll rt){
if(l>=L&&r<=R){
tree[rt].lazy = (C+tree[rt].lazy)%p;
tree[rt].val = (tree[rt].val+C*(r-l+1))%p;
return;
}
ll mid = (l+r)/2;
pushdown(mid-l+1,r-mid,rt);
if(mid>=L) updata1(L,R,C,l,mid,rt*2);
if(mid<R) updata1(L,R,C,mid+1,r,rt*2+1);
pushup(rt);
}
void updata2(ll L,ll R,ll C,ll l,ll r,ll rt){
if(l>=L&&r<=R){
tree[rt].lazy = tree[rt].lazy*C%p;
tree[rt].mul = tree[rt].mul*C%p;
tree[rt].val = (tree[rt].val*C)%p;
return;
}
ll mid = (l+r)/2;
pushdown(mid-l+1,r-mid,rt);
if(mid>=L) updata2(L,R,C,l,mid,rt*2);
if(mid<R) updata2(L,R,C,mid+1,r,rt*2+1);
pushup(rt);
}
ll ask(ll L,ll R,ll l,ll r,ll rt){
if(l>=L&&r<=R){
return tree[rt].val%p;
}
ll mid = (l+r)/2;
if(l>R||r<L)return 0;
pushdown(mid-l+1,r-mid,rt);
return (ask(L,R,l,mid,rt*2)+ask(L,R,mid+1,r,rt*2+1))%p;
}
int main(){
cin>>n>>p;
for(ll i = 1;i<=n;i++){
cin>>A[i];
}
cin>>m;
build(1,n,1);
while(m--){
ll x,y,a,c;
cin>>a>>x>>y;
if(a==1) {
cin>>c;
updata2(x,y,c,1,n,1);
}
else if(a==2){
cin>>c;
updata1(x,y,c,1,n,1);
}
else cout<<ask(x,y,1,n,1)%p<<'\n';
}
return 0;
}
二.数学
欧拉函数
求单个
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6+7;
int main(){
int T;
cin>>T;
while(T--){
ll x;
cin>>x;
ll res = x;
for(ll i = 2;i<=x/i;i++){
if(x%i==0){
while(x%i==0) x/=i;
res = res/i*(i-1);
}
}
if(x>1) res = res/x*(x-1);
cout<<res<<endl;
}
return 0;
}
线性求
void get_eulers(int n)
{
phi[1] = 1;
for (int i = 2; i <= n; i++)
{
if (!st[i])
{
primes[cnt++] = i;
phi[i] = i - 1;
}
for (int j = 0; primes[j] <= n / i; j++)
{
st[primes[j] * i] = true;
if (i % primes[j] == 0)
{
phi[primes[j] * i] = phi[i] * primes[j];
break;
}
phi[primes[j] * i] = phi[i] * (primes[j] - 1);
}
}
}
求逆元
1.费马小定理 inv[i] = pow(i,p-2) p为质数
2.exgcd
ll exgcd(ll a,ll b,ll & x,ll &y)
{
if(!b){
x = 1;
y = 0;
return a;
}
ll d = exgcd(b,a%b,y,x);
y -= x*(a/b);
return d;
}
3 . 线性递推
void init(){
inv[1] = 1;
for(int i = 2;i <= N;i++){
inv[i] = (p - p / i) * inv[p % i] % p;
}
}
组合数
- 递推
void init(){
for(int i=0;i<4000;i++){
for(int j=0;j<=i;j++){
if(!j) c[i][j]=1;
else c[i][j]=(c[i-1][j]+c[i-1][j-1])%MOD;
}
}
}
2.公式 Cba=a!/b!(a−b)!=a!∗b!−1∗(a−b)!−1
即求(b!)逆元和(a-b)!-1的逆元,递推即可
3.卢卡斯公式
int quick_power(int a, int k, int p)
{
int res = 1;
while (k) {
if (k & 1) {
res = (ll)res * a % p;
}
k >>= 1;
a = (ll)a * a % p;
}
return res;
}
int C(int a, int b, int p)
{
if (b > a) {
return 0;
}
int res = 1;
for (int i = 1, j = a; i <= b; i++, j--) {
res = (ll)res * j % p;
res = (ll)res * quick_power(i, p - 2, p) % p;
}
return res;
}
int lucas(ll a, ll b, int p)//a个里面调b个
{
if (a < p && b < p) {
return C(a, b, p);
}
return (ll)C(a % p, b % p, p) * lucas(a / p, b / p, p) % p;
}
矩阵加速
斐波那契求和
#include<bits/stdc++.h>
using namespace std;
const int N = 3;
typedef long long ll;
ll n,m;
ll A[N][N] = // 上述矩阵 A
{
{2, 0, -1},
{1, 0, 0},
{0, 1, 0}
};
ll S[N] = {2,1,0};
void cal(ll A[][N],ll B[][N]){
ll nw[N][N]={0};
for(ll i = 0;i<N;i++){
for(ll j = 0;j<N;j++){
for(ll k = 0;k<N;k++){
nw[i][j] += A[i][k]*B[k][j]%m;
}
}
}
for(ll i = 0;i<N;i++){
for(ll j = 0;j<N;j++){
A[i][j] = nw[i][j]%m;
}
}
}
void cal(ll A[],ll B[][N]){
ll nw[N] = {0};
for(ll i = 0;i<N;i++){
for(ll j = 0;j<N;j++){
nw[i] += A[j]*B[i][j]%m;
}
}
for(ll i = 0;i<N;i++){
A[i] = nw[i] % m;
}
}
int main(){
cin>>n>>m;
while(n){
if(n&1){
cal(S,A);
}
cal(A,A);
n>>=1;
}
cout<<((S[2]%m+m)%m)<<endl;
return 0;
}
三.基础算法
RMQ
ll A[N];
ll n;
ll fa[N][30];
int main(){
cin>>n;
for(int i = 1;i<=n;i++){
cin>>A[i];
fa[i][0] = A[i];
}
for(int i = 1;i<25;i++){
for(int j = 1;(1<<(i-1))+j<=n;j++){
fa[j][i] = max(fa[j][i-1],fa[j+(1<<(i-1))][i-1]);
}
}
int m;
cin>>m;
while(m--){
ll x,y;
cin>>x>>y;
int t=log2(y-x+1);
cout<<max(fa[x][t],fa[y-(1<<t)+1][t])<<endl;
}
return 0;
}
高精度
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+7;
vector<int> A(N),B(N),C(N);
string s,s2;
int len ,len2;
void input(vector<int > A,int ix){
if(ix<0) cout<<"0";
for(int i = ix;i>=0;i--)
cout<<A[i];
cout<<endl;
}
bool cmp(vector<int > A,vector<int > B){
if(len!=len2) return len>len2;
else {
for(int i = len-1;i>=0;i--){
if(A[i]>B[i]) return 1;
if(A[i]<B[i]) return 0;
}
}
return 1;
}
void add(){
int s = 0,i;
for( i = 0;i<=max(len,len2)+1;i++){
A[i] = s+A[i]+B[i];
s = A[i]/10;
A[i]%=10;
}
while(!A[i])i--;
input(A,i);
}
void sub(){
int s = 0,i;
if(cmp(A,B)==0) { C = B;
B = A;
A = C;
cout<<"-";
}
for( i = 0;i<max(len,len2);i++){
if(A[i]-B[i]-s<0) A[i] = (A[i]-s+10-B[i]),s=1;
else A[i]= A[i]-s-B[i],s=0;
}
while(!A[i])i--;
input(A,i);
}
void mul(){
for(int i = 0;i<len;i++){
for(int j = 0;j<len2;j++){
C[i+j] += A[i]*B[j];
C[i+j+1] += C[i+j]/10;
C[i+j]%=10;
}
}
int k = len+len2;
while(!C[k]&&k>0) k--;
input(C,k);
}
int main(){
cin>>s>>s2;
len = s.length();
len2 = s2.length();
A.resize(N),B.resize(N),C.resize(N);
for(int i = len-1,k=0;i>=0;i--,k++) A[k] = s[i]-'0';
for(int i = len2-1,k=0;i>=0;i--,k++) B[k] = s2[i]-'0';
return 0;
}
离散化
int C[MAXN], L[MAXN];
// 在main函数中...
memcpy(C, A, sizeof(A)); // 复制
sort(C, C + n); // 排序
int l = unique(C, C + n) - C; // 去重
for (int i = 0; i < n; ++i)
L[i] = lower_bound(C, C + l, A[i]) - C + 1; // 查找
__int128 手写输入输出
__int128 read(){
__int128 res = 0;
int sign = 1;
char ch;
if((ch=getchar())=='-1') sign = -1;
else res = res*10 + ch-'0';
while((ch=getchar())>='0'&&ch<='9'){
res = res*10 + ch-'0';
}
res *= sign;
return res;
}
void print(__int128 x ){
if(x<0){
x = -x;
printf("-");
}
if(x>9) print(x/10);
putchar(x%10 + '0');
}
二分
1答案的最大值,[l, r]划分成[l, mid]和[mid + 1, r]
int bsearch_1(int l, int r)
{
while (l < r)
{
int mid = l + r >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
return l;
}
2.答案的最小值,[l, r]划分成[l, mid - 1]和[mid, r]
int bsearch_2(int l, int r)
{
while (l < r)
{
int mid = l + r + 1 >> 1;
if (check(mid)) l = mid;
else r = mid - 1;
}
return l;
}
四.DP
数位DP
int dp[2000][10],A[N];
long long dfs(int pos ,int limit,int lead,int pre){
long long ans = 0;
if(pos<0) return 1;
if(!limit&&!lead&&dp[pos][pre]!=-1) return dp[pos][pre];
int up = limit?A[pos]:9;
for(int i = 0;i<=up;i++){
if(lead||abs(pre-i)>=2) ans+=dfs(pos-1,limit&&i==up,lead&&i==0,i);
}
if(!limit&&!lead) dp[pos][pre] = ans;
return ans;
}
long long slove(long long x){
int pos = 0;
memset(dp,-1,sizeof(dp));
while(x){
A[pos++] = x%10;
x/=10;
}
return dfs(pos-1,1,1,-2);
}