字符串
1.环串的最小表示
int getsmall(char s[]){ //以返回值开始的表示为最小串
int i=0,j=1,k=0;
while(i<len&&j<len&&k<len){
int tag=s[(j+k)%len]-s[(i+k)%len];
if(tag==0){
k++;
continue;
}
if(tag>0) //表示最大串改不等号
j+=k+1;
else
i+=k+1;
if(i==j) j++;
k=0;
}
return min(i,j);
}
2.扩展KMP
const int N = 101010;
int next[N],extand[N];
void getnext(char *T){ // next[i]: 以第i位置(下标为i)开始的子串 与 T的公共前缀
int i,length = strlen(T);
next[0] = length;
for(i = 0;i<length-1 && T[i]==T[i+1]; i++);
next[1] = i;
int a = 1;
for(int k = 2; k < length; k++){
int p = a+next[a]-1, L = next[k-a];
if( (k-1)+L >= p ){
int j = (p-k+1)>0? (p-k+1) : 0;
while(k+j<length && T[k+j]==T[j]) j++;// 枚举(p+1,length) 与(p-k+1,length) 区间比较
next[k] = j, a = k;
}
else next[k] = L;
}
}
void getextand(char *S,char *T){ //extand[i]: S下标为i开始的串和T的最长公共前缀
memset(next,0,sizeof(next));
getnext(T);
int Slen = strlen(S), Tlen = strlen(T), a = 0;
int MinLen = Slen>Tlen?Tlen:Slen;
while(a<MinLen && S[a]==T[a]) a++;
extand[0] = a, a = 0;
for(int k = 1; k < Slen; k++){
int p = a+extand[a]-1, L = next[k-a];
if( (k-1)+L >= p ){
int j = (p-k+1)>0? (p-k+1) : 0;
while(k+j<Slen && j<Tlen && S[k+j]==T[j] ) j++;
extand[k] = j;a = k;
}
else extand[k] = L;
}
}
3.manacher最长回文串
void manacher(int n){
p[0]=0;
int mx=0,id=0;
for(int i=1;i<n;i++){
if(mx>i)
p[i]=min(mx-i,p[2*id-i]);
else
p[i]=1;
while(ss[i+p[i]]==ss[i-p[i]])
p[i]++;
if(i+p[i]>mx){
mx=i+p[i];
id=i;
}
}
}
int main(){
while(~scanf(" %s",s)){
//预处理
int len=0;
ss[len++]='$';
ss[len++]='#';
for(int i=0;s[i];i++){
ss[len++]=s[i];
ss[len++]='#';
}
ss[len]=0;
manacher(len);// p[i]-1表示以i为中心的回文串在原串中的长度
int ans=1;
for(int i=0;i<len;i++)
if(p[i]>ans)
ans=p[i];
cout<<ans-1<<endl;
}
}
原串: w aa b wsw f d
新串: # w # a # a # b# w # s # w # f # d #
辅助数组P: 1 2 1 2 3 2 1 2 1 2 1 4 1 2 1 2 1 2 1
4.Tire
hdu2072
统计一篇文章中不同单词的个数。
const int maxnode=1000010;
struct Tire{
int ch[maxnode][26];
int val[maxnode];
int sz;
void clear(){
sz=1;
memset(ch[0],0,sizeof(ch[0]));
memset(val,0,sizeof(val));
}
int idx(char c){
return c-'a';
}
bool inserts(char s[]){
int u=0,n=strlen(s);
for(int i=0;i<n;i++){
int c=idx(s[i]);
if(!ch[u][c]){
memset(ch[sz],0,sizeof(ch[sz]));
ch[u][c]=sz;
val[sz]=0;
sz++;
}
u=ch[u][c];
if(i==n-1){
bool tag=val[u];
val[u]=1;
return tag;
}
}
}
bool searchs(char s[]){
int u=0,n=strlen(s);
for(int i=0;i<n;i++){
int c=idx(s[i]);
if(!ch[u][c])
return false;
u=ch[u][c];
}
return val[u];
}
};
Tire T;
string s;
char t[5000];
int main()
{
while(getline(cin,s),s[0]!='#'){
int ans=0;
T.clear();
int len=s.length();
for(int i=0;i<len;i++){
int j=0;
while(s[i]!=32&&s[i]){
t[j++]=s[i++];
}
t[j]=0;
if(j) ans+=!T.inserts(t);
}
printf("%d\n",ans);
}
return 0;
}
数学
1.线性筛
//素数线性筛
const int N=1000000;
bool ispri[N+5];
int pri[N],tot=0;
void make(){
memset(ispri,true,sizeof(ispri));
for(int i=2;i<N;++i){
if(ispri[i])
pri[tot++]=i;
for(int j=0;j<tot&&i*pri[j]<N;++j){ //遍历当前素数集
ispri[i*pri[j]]=0;
if(i%pri[j]==0) //任何一个合数都可以用最小的素数和另一个数的积表示
break; //若i含质因子pri[j]则i*pri[j+1]可以用另一个数与pri[j]的积筛
}
}
return ;
}
//素数线性筛+欧拉线性筛
void get_prime(){
phi[1]=1;
for(int i=2;i<maxn;i++){
if(!vis[i]){
prime[num_prime++]=i; //存素数
f[i]=i; //i的最小质因数为f[i]
phi[i]=i-1; //i的欧拉值
}
for(int j=0;j<num_prime&&i*prime[j]<maxn;j++){
vis[i*prime[j]]=true;
f[i*prime[j]]=prime[j];
if(i%prime[j]==0){
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
else
phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
}
//求n的所有约数,复杂度为n的约数个数
void dfs(int n,int res){
if(n==1){
printf("%d\n",res);
return ;
}
int x = n,t = f[n],cnt = 0; //f[n]为n的最小质因数
while(x%t==0) x/=t,++cnt;
dfs(x,res);
for(int i = 1; i <= cnt; ++i) {
res = res*t;
dfs(x,res);
}
}