模板整理3

FFT

给定一个 nn 次多项式 F(x)F(x),和一个 mm 次多项式 G(x)G(x)。

请求出 F(x)F(x) 和 G(x)G(x) 的卷积。

/*************************
User:Mandy.H.Y
Language:c++
Problem:luogu3803 FFT
Algorithm:
Date:2019.7.29
*************************/

#include<bits/stdc++.h>

using namespace std;

const int maxn = 5e6 + 5;
const double pi = acos(-1);

int n,m;
int r[maxn];

struct Complex{
	
	double r,i;
	
	inline Complex(){r  = i = 0;}
	inline Complex(register double x,register double y){r = x,i = y;}
	
	inline Complex operator +(register Complex &x){return Complex(r + x.r,i + x.i);}
	inline Complex operator -(register Complex &x){return Complex(r - x.r,i - x.i);}
	inline Complex operator *(register Complex &x){return Complex(r*x.r - i*x.i,r*x.i + i*x.r);}
	
	inline void operator +=(register Complex &x){r += x.r;i += x.i;}
	inline void operator *=(register Complex &x){register double t = r;r = r * x.r - i * x.i;i = t * x.i + i * x.r;}
}f[maxn],g[maxn];

void file(){
	freopen("FFT.in","r",stdin);
	freopen("FFT.out","w",stdout);
}

void readdata(){
	n = read();m = read();
	for(int i = 0;i <= n; ++ i) f[i].r = read();
	for(int i = 0;i <= m; ++ i) g[i].r = read();
}

inline void FFT(register Complex *a,register int opt){
	register Complex W,w,t,*a0,*a1;
	int j,k;
	for(int i = 0;i < n; ++ i){
		if(i < r[i]) t = a[i],a[i] = a[r[i]],a[r[i]] = t;
	}
	
	for(int i = 1;i < n;i <<= 1){
		for(W = Complex(cos(pi / i),sin(pi / i) * opt),j = 0;j < n;j += i << 1)
			for(w = Complex(1,0),a1 = i + (a0 = a + j),k = 0;k < i; ++ k, ++ a0,++ a1,w *= W)
				t = *a1 * w,*a1 = *a0 - t,*a0 += t;
	}
}

void work(){
	int l = 0;
	for(m += n,n = 1;n <= m;n <<= 1,++ l);
	
	for(int i = 0;i < n; ++ i) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (l - 1));
	
	FFT(f,1);FFT(g,1);
	
	for(int i = 0;i < n; ++ i) f[i] *= g[i];
	
	FFT(f,-1);
	
	for(int i = 0;i <= m; ++ i) printf("%.0lf ",fabs(f[i].r)/n);
}

int main(){
//	file();
	readdata();
	work();
	return 0;
}

mobius

/**********************
User:Mandy.H.Y
Language:c++
Problem:luogu2257
Algorithm:
Date:2019.8.2
Scores
**********************/
//n以内的素数大约是n/ln(n)个
#include<bits/stdc++.h>
#define Max(x,y) ((x) > (y) ? (x) : (y))
#define Min(x,y) ((x) > (y) ? (x) : (y))
//宏定义记得多打几个括号呀
//慎用慎用 
using namespace std;

typedef long long ll;

const int maxn = 1e7 + 5;
const int maxp = 1e6 + 5;

int t,n,m,cnt = 0;
int prime[maxp],mu[maxn];
int g[maxn];//g[i]中存的是i的所有 
long long sum[maxn];
bool not_prime[maxn];


void get_mu(){//线性筛求莫比乌斯函数 
	int MAXN = 1e7;
	not_prime[1] = 1; 
	not_prime[0] = 1;
	mu[1] = 1;//别忘了1 
	for(int i = 2;i <= MAXN; ++ i){
		if( ! not_prime[i]) prime[++cnt] = i,mu[i] = -1;
		for(int j = 1;j<=cnt && (ll)i * prime[j] <= (ll)MAXN; ++ j){//经验让我开long long
			not_prime[i * prime[j]] = 1;
			if(i % prime[j] == 0) break;
			else mu[i * prime[j]] = -mu[i];
		}
	}
	
	for(int i = 1;i <= cnt; ++ i) //枚举素数 
		for(int j = 1;(long long)j * prime[i] <= MAXN; ++ j) 
			g[j * prime[i]] += mu[j];
			
	for(int i = 1;i <= MAXN; ++ i) sum[i] = sum[i - 1] + (long long)g[i];
}

void work(){
	read(n);read(m);
	if(n > m) swap(n,m);
	//整除分块,没搞懂
	long long ans = 0;
	for(int l = 1,r;l <= n;l = r + 1){
		r = min(n / (n / l),m / (m / l));
		ans += ((long long)n/l) * (m/l) * (sum[r] - sum[l - 1]);
	}
	put(ans);
	puts("");
	
}

int main(){
//	file();
	read(t);
	get_mu();
	while(t --) work();
	return 0;
}

求区间第K大

【模板】可持久化线段树 1(主席树)

题目

题目传送门:luogu3834【模板】可持久化线段树 1(主席树)

代码
#include<bits/stdc++.h>
using namespace std;

const int maxn=2e5+5;

int n,m,len,cnt;
int a[maxn],dire[maxn],root[maxn];

struct node
{
	int l,r,sum;
}tree[maxn*20];//空间复杂度 O(N*logN) 
//开18会RE 
template<typename T>inline void read(T &x)
{
	x=0;bool f=0;char c=getchar();
	while(c<'0'||c>'9') {f|=(c=='-');c=getchar();}
	while(c>='0'&&c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	if(f) x=-x;
}

template<typename T>void putch(const T x)
{
	if(x>9) putch(x/10);
	putchar((x%10)|48);
}

template<typename T>void put(const T x)
{
	if(x<0) putchar('-'),putch(-x);
	else putch(x);
}

int getid(int x)
{
	return lower_bound(dire+1,dire+len+1,x)-dire;//-1+1
	//lower_bound返回第一个大于等于x的位置,upper_bound返回第一个大于x的位置 
}

void readdata()
{
	read(n);read(m);
	for(int i=1;i<=n;++i) {read(a[i]);dire[i]=a[i];}
	sort(dire+1,dire+n+1);
	len=unique(dire+1,dire+n+1)-dire-1;//减去首位置得到去重数列的长度 
	//unique排序,把重复的数排到后面,返回去重后的第一个重复的数的地址)
}

void update(int l,int r,int &x,int y,int k)//注意取址 ,x代表当前,y代表以前
{
	tree[++cnt]=tree[y];tree[cnt].sum++;x=cnt;//%%%%
	//自上而下的更新
	if(l==r) return;
	int mid=(l+r)>>1;
	if(mid>=k) update(l,mid,tree[x].l,tree[y].l,k);
	else update(mid+1,r,tree[x].r,tree[y].r,k);
	
}

int query(int l,int r,int x,int y,int k)
{
	if(l==r) return l;//返回位置 
	int sum=tree[tree[y].l].sum-tree[tree[x].l].sum;
	int mid=(l+r)>>1;
	//mid 是树上的位置,
	//sum是数值的左半部分的个数 
	
	if(k<=sum) return query(l,mid,tree[x].l,tree[y].l,k);
	else return query(mid+1,r,tree[x].r,tree[y].r,k-sum);
}

void work()
{
	for(int i=1;i<=n;++i) update(1,n,root[i],root[i-1],getid(a[i]));
	//unique针对的是相邻元素,所以对于顺序顺序错乱的数组成员,或者容器成员,需要先进行排序
	//以root[i]为根的树记录了第1~i个数的信息
	//每一个root[i]都是一颗完整线段树的根  
	for(int i=1;i<=m;++i)
	{
		int x,y,k;
		read(x);read(y);read(k);
		put(dire[query(1,n,root[x-1],root[y],k)]);
		putchar('\n');
	}
}

int main()
{
	readdata();
	work();
	return 0;
}

可持久化数组

【模板】可持久化数组(可持久化线段树/平衡树)

题目传送门:luogu3919【模板】可持久化数组(可持久化线段树/平衡树)

/***************************
User:Mandy.H.Y
Language:c++
Problem:luogu3919
Algorithm:
Date:2019.7.31
***************************/

/*
算法模型:可持久化线段树(主席树)

空间复杂度:O((n+m)logn)
时间复杂度:O((n+m)logn)其中
预处理:O(nlogn)
单次修改:O(logn)
单次查询:O(logn)
*/

#include<bits/stdc++.h>
#define lson l,mid
#define rson mid + 1,r
#define Max(x,y) (x) > (y) ? (x) : (y)
#define Min(x,y) (x) < (y) ? (x) : (y)

using namespace std;

const int maxn = 1e6 + 5;

int n,m,cnt,loc,change;
int root[maxn];

struct PST{
	int l,r,val;	
}tree[maxn * 25];
//开25倍,不然会RE 
template<class T>inline void read(T &x){
	x = 0;bool flag = 0;char ch = getchar();
	while( ! isdigit(ch)) flag |= ch == '-',ch = getchar();
	while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48),ch = getchar();
	if(flag) x = -x;
}

template<class T>void putch(const T x){
	if(x > 9) putch(x / 10);
	putchar(x % 10 | 48);
}

template<class T>void put(const T x){
	if(x < 0) putchar('-'),putch(-x);
	else putch(x);
}

void file(){
	freopen("tree.in","r",stdin);
//	freopen("tree.out","w",stdout);
}

void buildtree(int &cur,int l,int r){
	cur = ++cnt;
	//注意左右儿子 
	if(l == r){
		read(tree[cnt].val);
		tree[cnt].l = l,tree[cnt].r = r;
		return;
	}
	int mid = (l + r) >> 1;
	//左右儿子的修改 
	buildtree(tree[cur].l,lson);//cur 
	buildtree(tree[cur].r,rson);
	
}
	
void modify(int l,int r,int &cur,int pre){
	tree[++cnt] = tree[pre];
	cur = cnt;
	
	if(l == r){
		tree[cnt].val = change;
		return;
	}
	
	int mid = (l + r) >> 1; 
	//%%%cur
	//%%%  loc <= mid
	if(loc <= mid) modify(lson,tree[cur].l,tree[pre].l);
	else modify(rson,tree[cur].r,tree[pre].r);//cur
}

int query(int l,int r,int pre,int &cur){
	cur = ++cnt;
	tree[cnt] = tree[pre];
	
	if(l == r) return tree[pre].val;
	int mid = (l + r) >> 1;
	
	if(loc <= mid) return query(lson,tree[pre].l,tree[cur].l);
	else return query(rson,tree[pre].r,tree[cur].r);
	
}

void readdata(){
	read(n);read(m);
	buildtree(root[0],1,n);
}

void work(){
	
	for(int i = 1;i <= m; ++ i){
		int v,opt;
		read(v);read(opt);
		if(opt == 1){
			read(loc),read(change);
			modify(1,n,root[i],root[v]);
		}else{
			read(loc);
			put(query(1,n,root[v],root[i]));
			puts("");
		}
	}
}

int main(){
//	file();
	readdata();
	work();
	return 0;
}

高精度加法

/***************************************
User:Mandy.H.Y
Language:c++
Problem:luogu1601 A+B Problem(压位)
Algorhithm:High Precision Addition
****************************************/

#include<bits/stdc++.h>

using namespace std;

const int power=4; //压位压四位 
const int base=1e4;
const int maxn=505;

struct num{
	int a[maxn];
	
	num(){memset(a,0,sizeof(a));}
	
	int &operator [](int x){return a[x];}//重载中括号 
	
	num(char *s){
		
		memset(a,0,sizeof(a));
		int len=strlen(s);
		
		a[0]=(len+power-1)/power;//计算位数
		
		for(int i=0,t=0,w=0;i<len;++i,w*=10){
			if(i%power==0) {w=1,++t;}//最好写成这种形式 
			a[t]+=(s[i]-'0')*w;
			
		}
	}
	
	void print(){
		printf("%d",a[a[0]]);
		for(int i=a[0]-1;i>0;--i) printf("%04d",a[i]);//printf("%0*d",power,a[i]); 
	}
}ans,p,q;

num operator +(num &p,num &q){//重载了中括号所以不用const 
	int cur=0,len=max(p[0],q[0]);
	for(int i=1;i<=len;++i){
		cur+=i<=p[0]?p[i]:0;
		cur+=i<=q[0]?q[i]:0;
		p[i]=cur%base;cur/=base;
	}
	if(cur) p[++len]=cur;
	p[0]=len;//注意更新长度 
	return p;
}

char p1[maxn],q1[maxn];
int lenp,lenq;

int main(){
	scanf("%s%s",p1,q1);
	
	lenp=strlen(p1);lenq=strlen(q1);
	reverse(p1,p1+lenp);reverse(q1,q1+lenq);
	
	p=num(p1);q=num(q1);
	
	ans=p+q;
	ans.print();
	return 0;
}

高精度减法

/**************************************
User:Mandy.H.Y
Language:c++
Pronblem:luogu2142 A-B Problem
Algorhithm:High Precision Subtraction 
**************************************/

#include<bits/stdc++.h>

using namespace std;

const int power=4;
const int base=1e4;
const int maxn=1e4+5;

struct num{
	int a[maxn];
	
	num(){memset(a,0,sizeof(a));}
	
	num(char *s,int len){
		memset(a,0,sizeof(a));
		
		a[0]=(len+power-1)/power;
		
		for(int t=0,w=1,i=len-1;i>=0;w=(w<<1)+(w<<3),--i){//倒序省去reverse
			if((len-1-i)%power==0){++t,w=1;}
			a[t]+=(s[i]^48)*w;
		}
	}
	
	void print(){
		printf("%d",a[a[0]]);
		for(int i=a[0]-1;i>0;--i) printf("%0*d",power,a[i]);
	}
}p,q,ans;

bool operator <(const num &p,const num &q){//比较大小 
	if(p.a[0]<q.a[0]) return true;
	if(p.a[0]>q.a[0]) return false;
	for(int i=p.a[0];i>=1;--i){//倒序 
		if(p.a[i]!=q.a[i]) return p.a[i]<q.a[i];
	}
	return false;
}

num operator -(num &p,num &q){
	int len=max(p.a[0],q.a[0]);
	for(int i=1;i<=len;++i){
		p.a[i]-=i<=q.a[0]?q.a[i]:0;
		if(p.a[i]<0) p.a[i]+=base,p.a[i+1]-=1;//借位 
	}
	while(p.a[0]>1&&p.a[p.a[0]]==0) --p.a[0];
	return p;
}

char p1[maxn],q1[maxn];
int lenp,lenq;

int main(){
	scanf("%s%s",p1,q1);
	lenp=strlen(p1);lenq=strlen(q1);
	p=num(p1,lenp),q=num(q1,lenq);
	if(q<p) ans=p-q;
	else putchar('-'),ans=q-p;
	ans.print();
	return 0;
}

高精度乘法

/*********************************************

User:Mandy.H.Y
Language:c++
Problem:luogu 1303 A*B Problem
Algorithm: High Precision Multiplication

**********************************************/

#include<bits/stdc++.h>

using namespace std;

const int power=4;
const int base=1e4;
const int maxn=2e3+5;

struct num{
	int a[maxn<<1];
	
	num(){memset(a,0,sizeof(a));}
	
	num(char *s,int len){
		memset(a,0,sizeof(a));
		
		a[0]=(len+power-1)/power;
		
		for(int t=0,w=1,i=len-1;i>=0;w=(w<<1)+(w<<3),--i){
			if((len-1-i)%power==0) w=1,++t;
			a[t]+=(s[i]^48)*w;//注意+= 
		}
	}
	
	void print(){
		printf("%d",a[a[0]]);
		for(int i=a[0]-1;i>0;--i) printf("%0*d",power,a[i]);
	}
}ans,p,q;

char p1[maxn],q1[maxn];
int lenp,lenq;

num operator *(const num &p,const num &q){
	num b;
	for(int i=1;i<=p.a[0];++i){
		int cur=0;
		for(int j=1;j<=q.a[0];++j)
			cur+=b.a[i+j-1]+p.a[i]*q.a[j],b.a[i+j-1]=cur%base,cur/=base;
			//cur+=b.a[i+j-1]+p.a[i]*q.a[j]累加 b.a[i+j-1]
		b.a[i+q.a[0]]=cur;
	}
	b.a[0]=q.a[0]+p.a[0];//得到大致位数 
	while(b.a[0]>1&&b.a[b.a[0]]==0) --b.a[0];//除去前导0 
	return b;
}

int main(){
	scanf("%s%s",p1,q1);
	lenp=strlen(p1);lenq=strlen(q1);
	p=num(p1,lenp);q=num(q1,lenq);
	ans=p*q;
	ans.print();
	return 0;
}

整合

/**************************
User:Mandy.H.Y
Language:c++
Problem:
Algorithm: High Precision
***************************/

#include<bits/stdc++.h>

using namespace std;

const int power=4;
const int base=1e4;
const int maxn=2e3+5;

struct num{
	int a[maxn<<1];
	
	num(){memset(a,0,sizeof(a));}
	int &operator [](int x){return a[x];}//重载中括号 
	num(char *s,int len){
		memset(a,0,sizeof(a));
		
		a[0]=(len+power-1)/power;
		
		for(int t=0,w=1,i=len-1;i>=0;w=(w<<1)+(w<<3),--i){
			if((len-1-i)%power==0) w=1,++t;
			a[t]+=(s[i]^48)*w;//注意+= 
		}
	}
	void add(int k) { if (k || a[0]) a[ ++a[0] ] = k; }     //在末尾添加一个数,除法的时候要用到  
    void re() { reverse(a+1, a+a[0]+1); } 
	void print(){
		printf("%d",a[a[0]]);
		for(int i=a[0]-1;i>0;--i) printf("%0*d",power,a[i]);
	}
}ans,p,q;

char p1[maxn],q1[maxn];
int lenp,lenq;


num operator +(num &p,num &q){//重载了中括号所以不用const 
	int cur=0,len=max(p[0],q[0]);
	for(int i=1;i<=len;++i){
		cur+=i<=p[0]?p[i]:0;
		cur+=i<=q[0]?q[i]:0;
		p[i]=cur%base;cur/=base;
	}
	if(cur) p[++len]=cur;
	p[0]=len;//注意更新长度 
	return p;
}

bool operator <(const num &p,const num &q){//比较大小 
	if(p.a[0]<q.a[0]) return true;
	if(p.a[0]>q.a[0]) return false;
	for(int i=p.a[0];i>=1;--i){//倒序 
		if(p.a[i]!=q.a[i]) return p.a[i]<q.a[i];
	}
	return false;
}

num operator -(num &p,num &q){
	int len=max(p.a[0],q.a[0]);
	for(int i=1;i<=len;++i){
		p.a[i]-=i<=q.a[0]?q.a[i]:0;
		if(p.a[i]<0) p.a[i]+=base,p.a[i+1]-=1;//借位 
	}
	while(p.a[0]>1&&p.a[p.a[0]]==0) --p.a[0];
	return p;
}

num operator / (num &p,num &q)               //注意const不要冲突 
{  
    num x, y;  
    for (int i = p.a[0];i >= 1;--i)                       //从最高位开始取数  
    {  
        y.add(p.a[i]);             //把数添到末尾(最低位),这时候是高位在前,低位在后  
        y.re();                    //把数反过来,变为统一的存储方式:低位在前,高位在后  
        while ( !(y < q) )         //大于等于除数的时候,如果小于的话,其实答案上的该位就是初始的“0”  
            y = y - q, ++x.a[i];   //看能减几个除数,减几次,答案上该位就加几次。  
        y.re();                    //将数反过来,为下一次添数做准备  
    }  
    x.a[0] = p.a[0];  
    while (x.a[0] > 0 && !x.a[x.a[0]]) --x.a[0];  
    return x;  
}  

num operator *(const num &p,const num &q){
	num b;
	for(int i=1;i<=p.a[0];++i){
		int cur=0;
		for(int j=1;j<=q.a[0];++j)
			cur+=b.a[i+j-1]+p.a[i]*q.a[j],b.a[i+j-1]=cur%base,cur/=base;
		b.a[i+q.a[0]]=cur;
	}
	b.a[0]=q.a[0]+p.a[0];//得到大致位数 
	while(b.a[0]>1&&b.a[b.a[0]]==0) --b.a[0];//除去前导0 
	return b;
}

int main(){
	
	/*
	scanf("%s%s",p1,q1);
	lenp=strlen(p1);lenq=strlen(q1);
	p=num(p1,lenp);q=num(q1,lenq);
	ans=p*q;
	ans.print();
	return 0;
	*/
	
	
	scanf("%s%s",p1,q1);
	
	lenp=strlen(p1);lenq=strlen(q1);
	
	p=num(p1,lenp);q=num(q1,lenq);
	
	ans=p+q;
	ans.print();
	return 0;
	
	
	
	/*
	
	scanf("%s%s",p1,q1);
	lenp=strlen(p1);lenq=strlen(q1);
	p=num(p1,lenp),q=num(q1,lenq);
	if(q<p) ans=p-q;
	else putchar('-'),ans=q-p;
	ans.print();
	return 0;

	*/
	
}

部分引自:https://www.cnblogs.com/hnqw1214/p/6351321.html

KMP

如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置。

/*
ID:胡芸 Mandy
language:c++
algorithm:KMP 
*/
#include<bits/stdc++.h>

#define M 1000003
#define N 1000003
#define Max(x,y) (x)>(y)?(x):(y)
#define Min(x,y) (x)<(y)?(x):(y)
#define up(i,l,r) for(int i=l;i<=r;++i)
#define down(i,l,r) for(int i=r;i>=l;--i)

using namespace std;

int pre[N]; 
char mat[N],pat[N];

void init()
{
	pre[0]=-1;
	pre[1]=0;
	int i=0,j=-1,n=strlen(pat);
	while(i<n)
	{
		if(j==-1||pat[i]==pat[j]) pre[++i]=++j;
		else j=pre[j];
	}
}

void kmp()
{
    init();
    int n=strlen(mat),m=strlen(pat)-1;
    int i=0,j=0;
    while(i<n)
	{
    	if(j==-1||mat[i]==pat[j])
    	{
    		if(j==m)
    		{
    			printf("%d\n",i-m+1);
    			j=pre[j];
			}
			else
			{
				i++;
				j++;
			}
		}
		else
		{
			j=pre[j];
		}
	}
}

int main()
{
	scanf("%s\n%s",mat,pat);
	kmp();
	int n= strlen(pat);
	up(i,1,n)
	{
		printf("%d ",pre[i]);
	} 
	return 0;
}

ManACher

给出一个只由小写英文字符a,b,c…y,z组成的字符串S,求S中最长回文串的长度.

字符串长度为n

/****************************
User:Mandy.H.Y
Language:c++
Problem:luogu3085
Algorithm:Manacher
****************************/

#include<bits/stdc++.h>

using namespace std;

const int maxn=11000005;

int len[maxn<<1],len1,len2;
char s[maxn],str[maxn<<1];

void docu()
{
	freopen("3085.txt","r",stdin);
}

void init()
{
	len2=0;
	str[len2++]='$';
	len1=strlen(s);
	for(int i=0;i<len1;++i)
	{
		str[len2++]='#';
		str[len2++]=s[i];
	}
	str[len2++]='#';//!!!
}

int Manacher()
{
	int id=1,mx=1,sum=0;
	for(int i=2;i<len2;++i)
	{
		if(i<mx) len[i]=min(len[(id<<1)-i],mx-i);
		else len[i]=1;
		while(i+len[i]<=len2&&i-len[i]>=0&&str[i+len[i]]==str[i-len[i]]) ++len[i];//i+len[i]<=len2&&i-len[i]>=0
		if(i+len[i]>mx)
		{
			mx=i+len[i];
			id=i;
			sum=max(sum,len[i]);
		}
	}
	return sum-1;
}

void work()
{
	int ans=Manacher();
	printf("%d",ans);
}

int main()
{
//	docu();
	scanf("%s",s);
	init();
	work();
}

后缀数组

读入一个长度为 n n 的由大小写英文字母或数字组成的字符串,请把这个字符串的所有非空后缀按字典序从小到大排序,然后按顺序输出后缀的第一个字符在原串中的位置。位置编号为 1 1 到 n n。

/**********************
User:Mandy.H.Y
Language:c++
Problem:luogu3809 Suffix Sorting
Algorithm:Suffix Array
Date:2019.7.19
Scores:
**********************/
//指针是程序员的杀手
//怕了怕了 
//x:一开始是原始数据r的拷贝
//(其实也表示长度为1的字符串的排名),之后表示k/2长度字符串的排名.
//y:指示长度为k 的字符串的第二关键字的排序结果
//通过存储k长字符串的第一关键字的下标进行指示.
#include<bits/stdc++.h>

using namespace std;

const int maxn = 1e6 + 5;

int n;
int w[155],a[maxn],sa[maxn],a1[maxn];
char c[maxn];
int x[maxn],y[maxn];

void file(){
	freopen("3809.in","r",stdin);
	freopen("3809.out","w",stdout);
}

void readdata(){
	scanf("%s",c);
	n = strlen(c);
	for(int i = 0;i < n; ++ i)
		a[i] = c[i] - '0' + 1;
}

void get_SA(int m){
	
//	int *x = a,*y = a1;
	
	for(int i = 0;i < m; ++ i) w[i] = 0;
	for(int i = 0;i < n; ++ i) ++ w[x[i] = a[i]];
	for(int i = 1;i < m; ++ i) w[i] += w[i - 1];
	for(int i = n - 1;i >= 0; -- i) sa[ -- w[x[i]]] = i;
	//倒序保证在字母相同的情况下编号小的在前面 
	
	for(int k = 1;k <= n;k <<= 1){
		
		int p = 0;
		
		for(int i = n - k;i < n; ++ i) y[p ++ ] = i;
		for(int i = 0;i < n; ++ i) if(sa[i] >= k) y[p ++ ] = sa[i] - k;
		
		for(int i = 0;i < m; ++ i) w[i] = 0;
		for(int i = 0;i < n; ++ i) ++ w[x[y[i]]];
		for(int i = 1;i < m; ++ i) w[i] += w[i - 1];
		for(int i = n - 1;i >= 0; -- i) sa[ -- w[x[y[i]]]] = y[i];
		
		swap(x,y);x[sa[0]] = 0;
		p = 1;//初始化
		for(int i = 1;i < n; ++ i){
			x[sa[i]] = y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k] ? p - 1 : p ++;
		}
		
		if(p >= n) break;
		m = p;
		
	}
}

int rank[maxn],height[maxn];

void  get_height(){
	for(int i = 0;i < n; ++ i) rank[sa[i]] = i;
	int  k = 0;
	for(int i = 0;i < n; ++ i){
		if(k) -- k;
		if(rank[i] == 0) continue; 
		//第一名height为0 
		int j = sa[rank[i] - 1];//排名在i的前一个的编号 
		while(a[i + k] == a[j + k]) ++k;
		//标号从零开始,k为个数
		height[rank[i]] = k; //height[rank[i]]
	}
}

void work(){
	get_SA(150); 
//	get_height();
	for(int i = 0;i < n; ++ i) printf("%d ",sa[i] + 1);
	
}

int main(){
//	file();
//	freopen("testdata.in","r",stdin);
	readdata();
	work();
	return 0;
}

模拟退火

/*
User:Mandy
Language:c++
Problem:1337
*/
//emmmm,注意double,然后参数可以调大点 ,注意时间 
#include<bits/stdc++.h>
#define RD T*(rand()*2-RAND_MAX)

using namespace std;

const int maxn=1005;
const long double EPS=1e-16;
const long double D=0.98;

int n;
long double ansx,ansy,minans,curans;
long double x[maxn],y[maxn],w[maxn];

void readdata()
{
	scanf("%d",&n);
	for(int i=1;i<=n;++i)
	{
		scanf("%Lf%Lf%Lf",&x[i],&y[i],&w[i]);
		ansx+=x[i];
		ansy+=y[i];
	}
}

long double get(long double x0,long double y0)
{
	long double sum=0;
	for(int i=1;i<=n;++i)
	{
		long double nx=x0-x[i];
		long double ny=y0-y[i];
		sum+=(sqrt(nx*nx+ny*ny))*w[i];
	}
	return sum;
}

void work()
{
	srand(20030110);
	ansx/=n;ansy/=n;
	minans=get(ansx,ansy);
	int Time=2;
	long double curx,cury;
	while(Time--)
	{
		
		curans=minans;curx=ansx;cury=ansy;
		for(long double T=100000;T>EPS;T*=D)
		{
			
			long double xx=curx+RD,yy=cury+RD;
			long double sum=get(xx,yy);
			//printf("%.5Lf %.5Lf %.5Lf\n",xx,yy,sum);
			if(minans>sum)
			{
				minans=sum;ansx=xx;ansy=yy;
			}
			if(curans>sum||exp((curans-sum)/T)>(long double)rand()/RAND_MAX)
			{
				curans=sum;curx=xx;cury=yy;
			}
		}
	}
	printf("%.3Lf %.3Lf",ansx,ansy);
}

int main()
{
	readdata();
	work();
	return 0;
}

AC自动机

有NN个由小写字母组成的模式串以及一个文本串TT。每个模式串可能会在文本串中出现多次。你需要找出哪些模式串在文本串TT中出现的次数最多。

/*
User:Mandy.H.Y
Language:c++
problem:luogu3796 
*/

#include<bits/stdc++.h>

#define Max(x,y) (x)>(y)?(x):(y)
#define Min(x,y) (x)<(y)?(x):(y)
#define mem(A) memset((A),0,sizeof(A))
#define up(i,l,r) for(int i=l;i<=r;++i) 
#define down(i,l,r) for(int i=r;i>=l;--i)

using namespace std;

const int MAXM=1e6+2;
const int MAXN=11000;

int n,cnt,len;
int tree[MAXN][27],fail[MAXN],ans[153];
int mark[MAXN];
char str[MAXM],str1[152][73];

void docu()
{
	freopen("1.txt","r",stdin);
}

void readdata()
{
	scanf("%d",&n);
}

void init()
{
	cnt=0;
	mark[0]=0;
	memset(tree[0],0,sizeof(tree[0]));
}

void buildtree(int size)
{
	int root=0;
	up(i,0,len-1)
	{
		int pos=str1[size][i]-'a';
		if(!tree[root][pos])
		{
			tree[root][pos]=++cnt;
			memset(tree[cnt],0,sizeof(tree[cnt]));
			mark[cnt]=0;
		}
		root=tree[root][pos];
	}
	ans[size]=0;
	mark[root]=size;
}

void getfail()
{
	queue<int>q;
	up(i,0,25)
	{
		if(tree[0][i])
		{
			fail[tree[0][i]]=0;
			q.push(tree[0][i]);
		}
	}
	while(!q.empty())
	{
		int root=q.front();
		q.pop();
		up(i,0,25)
		{
			if(tree[root][i])
			{
				fail[tree[root][i]]=tree[fail[root]][i];
				q.push(tree[root][i]);
			}
			else tree[root][i]=tree[fail[root]][i];
		}
	}
}

void find()
{
	int root=0;
	int maxans=0,tp=0;
	int ans1[152];
	up(i,0,len-1)
	{
		int pos=str[i]-'a';
		root=tree[root][pos];
		for(int j=root;j;j=fail[j])
		{
			if(!mark[j]) continue;
			ans[mark[j]]++;
			if(ans[mark[j]]>maxans)
			{
				maxans=ans[mark[j]];
				tp=0;
				ans1[0]=mark[j];
			}
			else if(ans[mark[j]]==maxans)
			{
				ans1[++tp]=mark[j];
			}
		}
	}
	sort(ans1,ans1+tp+1);
	printf("%d\n",maxans);
	up(i,0,tp)
	{
		printf("%s\n",str1[ans1[i]]);
	}
}

void work()
{
	while(n)
	{
		init();
		up(i,1,n)
		{
			scanf("%s",str1[i]);
			len=strlen(str1[i]);
			buildtree(i);
		}
		scanf("%s",str);
		len=strlen(str);
		getfail();
		find();
		scanf("%d",&n);
	}
}

int main()
{
//	docu();
	readdata();
	work();
	return 0;
}

字典树

//建树(其实就是存点啦)
struct nodes{
    int son[26];
//此处只考虑小写字母字典树
    bool mark;
// 此为标记,作用下面说 
}trie[10001]; 
int root=0,num=0;
//根节点永久为0 qwq 
bool insert_check(char *str)
{
    int position=root;//初始化位置,跟深度没有直接关系 
    for(int i=0;str[i];i++)
    {
        int symbol=(int)str[i]-'a';
/*此处实际是因为我们的trie都是存int的,如果贸然存char会
很别扭qwq,并且此处由于都是小写字母,所以 -‘a’ ,如果
存了别的类型的字符,需要特判,保证字符容易确定 */  
        if(!trie[position].son[symbol]) //还没有被编号
        trie[position].son[symbol]=++num;//编一个号

        position=trie[position].son[symbol] ;
        //更新迭代位置,直到字符链的最末端 
    } 
    int temp=trie[position].mark;
    trie[position].mark =1;
//将这条链的最末端置为1,如果还有重复的串,那么一定会出现
//最末端相同 ;反之,最末端节点的mark相同也可以推出链相同,
//借此来判断串是否相同 
    return temp!=0;
/*最后说一下为什么要编号:我们根据程序可以看出,字符串是
按秩插入树,所以一条链上的编号肯定满足单调,便于我们查找
和比对*/ 
} 
int root=0;
bool find(char* str)
{
    int pos=root;
    for(int i=0;str[i];i++)
    {
        int x=str[i]-'a';
        if(trie[pos].son[x]==0)return false;
        //如果在建完树之后这个点还没有被编号,
        //那么就肯定不存在这条链。(互异性) 
        pos=trie[pos].son[x] ;//继续迭代 
    }
    return true; 
}

HASH

单hash

#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll int
#define inf 1<<30
#define mt(x,y) memset(x,y,sizeof(x))
#define il inline 
#define ull unsigned long long
il ll max(ll x,ll y){return x>y?x:y;}
il ll min(ll x,ll y){return x<y?x:y;}
il ll abs(ll x){return x>0?x:-x;}
il ll swap(ll x,ll y){ll t=x;x=y;y=t;}
il void read(ll &x){
    x=0;ll f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-f;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    x*=f;
}
using namespace std;
#define N 10001
#define base 233
ull mod=212370440130137957ll;
ll f[N],n;
char a[N];
ull hash(char s[]){
    ull ans=0,len=strlen(s);
    for(ll i=0;i<len;i++){
        ans=base*ans+(ull)s[i];
        //这里不使用mod让它自然溢出,定义为ull的数在超过2^32的时候会自然溢出
        //如果把这个换成上面的hash就会400ms+
        //所以说自然溢出大法好
    }
    return ans;
}
int main(){
    read(n);
    for(ll i=1;i<=n;i++){
        scanf("%s",a);
        f[i]=hash(a);
    }
    sort(f+1,f+n+1);ll ans=1;
    for(ll i=1;i<n;i++){
        if(f[i]!=f[i+1])ans++;
    }
    printf("%d\n",ans);
    return 0;
}
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll int
#define inf 1<<30
#define mt(x,y) memset(x,y,sizeof(x))
#define il inline 
#define ull unsigned long long
il ll max(ll x,ll y){return x>y?x:y;}
il ll min(ll x,ll y){return x<y?x:y;}
il ll abs(ll x){return x>0?x:-x;}
il ll swap(ll x,ll y){ll t=x;x=y;y=t;}
il void read(ll &x){
    x=0;ll f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-f;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    x*=f;
}
using namespace std;
#define N 10001
#define base 233
ull mod1=212370440130137957ll;
ull mod2=inf;
ll n;
char a[N];
struct node{ll x,y;}f[N];
il ull hash1(char s[]){
    ll ans=0,len=strlen(s);
    for(ll i=0;i<len;i++){
        ans=(base*ans+(ull)s[i])%mod1;
    }
    return ans;
}
il ull hash2(char s[]){
    ll ans=0,len=strlen(s);
    for(ll i=0;i<len;i++){
        ans=(base*ans+(ull)s[i])%mod2;
    }
    return ans;
}
il bool cmp1(node a,node b){return a.x<b.x;}
il bool cmp2(node a,node b){return a.y<b.y;}
int main(){
    read(n);
    for(ll i=1;i<=n;i++){
        scanf("%s",a);
        f[i].x=hash1(a);
        f[i].y=hash2(a);
    }
    sort(f+1,f+n+1,cmp1);sort(f+1,f+n+1,cmp2);
    ll ans=1;
    for(ll i=1;i<n;i++){
        if(f[i].x!=f[i+1].x||f[i].y!=f[i+1].y)ans++;
    }
    printf("%d\n",ans);
    return 0;
}

最大流

/*
ID:胡芸 Mandy
language:c++
problem:luogu3376 Maximum flow 
*/
#include<bits/stdc++.h>

#define M 100005
#define N 10005
#define Maxint (1<<31)-1
#define Max(x,y) (x)>(y)?(x):(y)
#define Min(x,y) (x)<(y)?(x):(y)
#define up(i,l,r) for(int i=l;i<=r;++i)
#define down(i,l,r) for(int i=r;i>=l;--i)

using namespace std;

struct Edge
{
	int v,w,nt;
}edge[M<<1];//因有虚拟边,要开二倍 
int n,m,s,t,first[N],size,ans,dist[N],cur[N];

inline int read()
{
	int x=0;char c=getchar();
	while(c<'0'||c>'9') c=getchar();
	while(c>='0'&&c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x;
}

inline void put(int x)
{
	if(x==0) {putchar('0');return;}
	int num=0;char c[15];
	while(x) {c[++num]=(x%10)|48; x/=10;}
	while(num) putchar(c[num--]); 
}

void docu()
{
	freopen("3376.in","r",stdin);
	freopen("3376.out","w",stdout);
}

void eadd(int u,int v,int w)
{
	edge[++size].v=v;
	edge[size].w=w;
	edge[size].nt=first[u];
	first[u]=size;
}

void readdata()
{
	n=read(); m=read(); s=read(); t=read();
	up(i,1,m)
	{
		int u=read(),v=read(),w=read();
		eadd(u,v,w);
		eadd(v,u,0);
	}
}

bool bfs()
{
	memset(dist,0,sizeof(dist));
	queue<int>q;
	q.push(s);
	dist[s]=1;
	while(!q.empty())
	{
		int u=q.front();
		q.pop();
		for(int i=first[u];i;i=edge[i].nt)
		{
			int v=edge[i].v;
			if(edge[i].w>0&&!dist[v])
			{
				dist[v]=dist[u]+1;
				q.push(v);
			}
		}
	}
	if(dist[t]) return 1;
	else return 0;
}

int dfs(int u,int init)
{
	if(u==t||init==0) return init;
	int left=init;
	for(int i=cur[u];i;i=edge[i].nt)
	{
		cur[u]=i;
		int v=edge[i].v;
		if(dist[v]==dist[u]+1&&edge[i].w>0)
		{
			int maxf=dfs(v,Min(edge[i].w,left));
			edge[i].w-=maxf;
			edge[i+1].w+=maxf;
			left-=maxf;
			if(left<=0)
			{
				left=0;
				break;
			}
		}
	}
	return init-left;
}

void Dinic()
{
	while(bfs())
	{
		up(i,1,n) cur[i]=first[i];
		ans+=dfs(s,Maxint);
	}
}

void work()
{
	Dinic();
	put(ans);
}

int main()
{
//	docu();
	readdata();
	work();
	return 0;
}

最小费用最大流

/*
ID:胡芸 Mandy
language:c++
problem:luogu3381 Minimum cost maximum flow
*/
#include<bits/stdc++.h>

#define M 50005
#define N 5005
#define Maxint (1<<30)-2
#define Max(x,y) (x)>(y)?(x):(y)
#define Min(x,y) (x)<(y)?(x):(y)
#define up(i,l,r) for(int i=l;i<=r;++i)
#define down(i,l,r) for(int i=r;i>=l;--i)

using namespace std;

int n,m,s,t,first[N],dist[N],size=1,ansflow=0,anscost=0;//size从二开始 ,好用异或 
bool vis[N];
int cur[N]; 
struct Edge
{
	int v,w,f,nt;
}edge[M<<1];

inline int read()
{
	int x=0;char c=getchar();
	while(c<'0'||c>'9') c=getchar();
	while(c>='0'&&c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x;
}

inline void put(int x)
{
	if(x==0) {putchar('0');return;}
	int num=0;char c[15];
	while(x) {c[++num]=(x%10)|48; x/=10;}
	while(num) putchar(c[num--]); 
}

void docu()
{
	freopen("3381.in","r",stdin);
//	freopen("3381.out","w",stdout);
}

void eadd(int u,int v,int f,int w)
{
	edge[++size].v=v;
	edge[size].w=w;
	edge[size].f=f;
	edge[size].nt=first[u];
	first[u]=size;
}

void readdata()
{
	n=read();m=read();s=read();t=read();
	up(i,1,m)
	{
		int u=read(),v=read(),f=read(),w=read();
		eadd(u,v,f,w);
		eadd(v,u,0,-w);
	}
}

bool SPFA()
{
	queue<int>q;
	memset(dist,0x3f3f3f3f,sizeof(dist));
	memset(vis,0,sizeof(vis));
	q.push(s);
	vis[s]=1;
	dist[s]=0;
	while(!q.empty())
	{
		int u=q.front();
		q.pop();
		vis[u]=0;
		for(int i=first[u];i;i=edge[i].nt)
		{
			int v=edge[i].v,w=edge[i].w;
			if(dist[u]+w<dist[v]&&edge[i].f>0)
			{
				dist[v]=dist[u]+w;
				if(!vis[v])
				{
					q.push(v);
					vis[v]=1;
				}
			}
		}
	}
	if(dist[t]==0x3f3f3f3f) return 0;
	else return 1;
}

int dfs(int u,int init)
{
	if(u==t||init==0) return init;
	int left=init;
	vis[u]=1;
	for(int i=cur[u];i;i=edge[i].nt)
	{
		int v = edge[i].v;
		cur[u]=i;
		if(edge[i].f>0&&!vis[v]&&dist[v]==dist[u]+edge[i].w)
		{
			int maxf=dfs(v,Min(left,edge[i].f));//注意Min 
			anscost+=maxf*edge[i].w;
			edge[i].f-=maxf;
			left-=maxf;
			edge[i^1].f+=maxf;
			//虚拟边也有可能退流,应为是染色,
			//所以前面可能没走完,不能用+1 
			//费用流不用当前弧优化,
			//因为用SPFA标记最短路,不像最大流是分层,
			//会陷入死循环,用染色保证每个点只走一次
			//可以当前弧优化和染色一起用; 
			if(left<=0)
			{
				left=0;
				break;
			}
		}
	}
	return init-left;
}

void Dinic()
{
	while(SPFA())
	{
		for(int i=1;i<=n;++i) cur[i]=first[i];
		ansflow+=dfs(s,Maxint);
	}
}

void work()
{
	Dinic();
	put(ansflow);
	putchar(' ');
	put(anscost);
}

int main()
{
//	docu();
	readdata();
	work();
	return 0;
}

康托展开

排列的排名
a n s = 1 + ∑ i = 1 n A [ i ] × ( n − i ) ! ans = 1 + \sum_{i=1}^{n}{A[i]×(n−i)!} ans=1+i=1nA[i]×(ni)!

#include<bits/stdc++.h>
using namespace std;
#define MAXN 1000005
#define rgt register
#define mod 998244353

int N, a[MAXN], fac, c[MAXN], ans;
char *p;

inline void read( rgt int &x ){
    x = 0; while( !isdigit(*p) ) ++p;
    while( isdigit(*p) ) x = x * 10 + ( *p & 15 ), ++p;
}

int main(){
    scanf( "%d", &N ), fac = 1;
    p = new char[N * 8 + 100],
    fread( p, 1, N * 8 + 100, stdin );
    for ( rgt int i = N; i; --i ) read(a[i]);
    for ( rgt int i = 1, s, j; i <= N; ++i ){
        for ( s = 0, j = a[i]; j; j -= j & -j ) s += c[j];
        ans = ( ans + 1ll * fac * s ) % mod, fac = 1ll * fac * i % mod;
        for ( j = a[i]; j <= N; j += j & -j ) ++c[j];
    } printf( "%d\n", ans + 1 );
    return 0;
}

二分图

/*
ID:胡芸 Mandy
language:c++
problem:luogu 3386
*/
#include<bits/stdc++.h>

#define N 1002
#define M 1000003
#define Max(x,y) (x)>(y)?(X):(y)
#define Min(x,y) (x)<(y)?(x):(y)
#define up(i,l,r) for(int i=l;i<=r;++i)
#define down(i,l,r) for(int i=r;i>=l;--i)

using namespace std;

int n,m,tot,f[N],s,visn[M];
bool vism[M];

struct Edge
{
	int v,nt;
}e[M];

inline int read()
{
	int x=0; char c=getchar();
	while(c<'0'||c>'9') c=getchar();
	while(c>='0'&&c<='9') {x=(x<<3)+(x<<1)+(c^48); c=getchar();}
	return x;
} 

inline void put(int x)
{
	if(x==0) {putchar('0'); return;}
	int num=0;char c[21];
	while(x) {c[++num]=(x%10)^48; x/=10;}
	while(num) putchar(c[num--]);
}

void docu()
{
	freopen("3386.in","r",stdin);
	freopen("3386.out","w",stdout); 
} 

void eadd(int u,int v)
{
	e[++s].v=v;
	e[s].nt=f[u];
	f[u]=s;
}

void readdata()
{
	n=read();
	m=read();
	tot=read();
	up(i,1,tot)
	{
		int u=read(),v=read();
		if(u>n||v>m) continue;
		eadd(u,v);
	}
}

bool match(int u)
{
	for(int i=f[u];i;i=e[i].nt)
	{
		int v=e[i].v;
		if(!vism[v])
		{
			vism[v]=1;
			if(!visn[v]||match(visn[v]))
			{
				visn[v]=u;
				return 1;
			}
		}
	}
	return 0;
}

void work()
{
	int ans=0;
	up(i,1,n)
	{
		memset(vism,0,sizeof(vism));
		if(match(i)) ans++;
	}
	printf("%d",ans);
}

int main()
{
	//docu();
	readdata();
	work();
	return 0;
} 

输入输出

1.char[]char buf[1000005];

cin.getline(buf,sizeof(buf));

多行文件输入的情况:

while(cin.getline(buf,sizeof(buf)))......

 

2.string 型

string buf;

getline(cin,buf)

 

3.用fgets函数

char buf[1000005];

fgets(buf,1000005,stdin);

多行文件输入的情况:

while(fgets(buf,1000005,stdin)!=NULL)......
————————————————
版权声明:本文为优快云博主「erge1998」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.youkuaiyun.com/linruier2017/article/details/84031438
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值