文章目录
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]×(n−i)!
#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