10
25
2015
0

KMP+Manacher学习笔记

KMP是一种可以在最坏O(n+m)的时间内完成匹配的字符串匹配算法。学了这个也有一些时间了,也是时候写一点学习笔记了。

KMP需要处理一个next数组,也就是当匹配失败后应该跳转到的匹配位置。

算法如下(懒癌晚期,简直啥也没说)

UPD:代码里面有一个明显的错误今天才发现……我水平怎么这么低……为被坑到的同学们道个歉……555 ——2016.6.21

char a[1000005],b[105];
int next[105];
//a表示需要匹配的串,b表示模式串

void Fill() {
next[1]=0;
int n=strlen(a+1);
for(int i=2,j=0;i<=n;i++) {
    while(j>0&&a[i]!=a[j+1])j=next[j];
    if(a[i]==a[j+1])j++;
    next[i]=j;
}
}

//以下Find函数的mode意思是:当mode=0时,输出匹配成功的位置;mode=1时,输出出现的次数.

int Find(int mode){
Fill();
int ans=0;
int n=strlen(a+1),m=strlen(b+1);
for(int i=1,j=0;i<=m;i++) {
    while(j>0&&(j==n||b[i]!=a[j+1]))j=next[j];
    if(b[i]==a[j+1])j++;
    if(j==n)ans++;
}
return ans;
}

接下来是Manacher算法。

这是一种可以O(n)解决回文子串的算法。详见这里

你萌不觉得我的代码简直就是背模版么233

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int p[240005],len;
char s[240005];

int main(){
freopen("3068.in","r",stdin);
freopen("3068.out","w",stdout);
while(scanf("%s",s)!=EOF){
    int len=strlen(s),id=0,maxlen=0;
    for(int i=len;i>=0;i--){
        s[i*2+1]='#';
        s[i*2+2]=s[i];
    }
    s[0]='*';
    s[len*2+3]='\0';
    for(int i=2;i<2*len+1;i++){
        if(p[id]+id>i){
            p[i]=min(p[id*2-i],p[id]+id-i);
        }
        else p[i]=1;
        while(s[i-p[i]]==s[i+p[i]])p[i]++;
        if(id+p[id]<i+p[i])id=i;
        if(p[i]>maxlen)maxlen=p[i];
    }
    printf("%d\n",maxlen-1);
}
return 0;
}
Category: OI | Tags: OI
10
16
2015
1

单调队列训练

http://hzwer.com/?s=%E5%8D%95%E8%B0%83%E9%98%9F%E5%88%97

已经做了几题:

1

Category: OI | Tags: OI
10
15
2015
1

多重背包单调队列优化的理解

其实我早就会写多重背包了……只不过是写成做多次01背包而已……

看着大爷秒题,我心中感到自己好弱啊。

于是我就来理解一下多重背包的单调队列做法,并记录在这里。

对于一个物品有个数限制的背包,我们考虑状态转移方程:

f[now][j]=max(f[last][j],f[last][j-w[i]*k]+c[i]*k),其中w[i]为重量,c[i]为价值。

感觉要枚举i,j,k,然后时间复杂度就爆炸了……

怎么办?用单调队列!

因为当我们取到了最大的f[last][j-w[i]*k]+c[i]*k时,再往下取k就没有意义了(不可能大于这个值)

所以我们维护一个单调队列,使队首为最大值,每次把不符合的队首删去,同时把队尾小于我们枚举的f[last][j-w[i]*k]+c[i]*k删去。

队列中存的是k,也就是记录当前取了多少个该物品,即可。

下面是一道例题。

----------------------------------------------------------------

超市购物

Description

Bob家附近新开了一家超市。最近,超市开展了促销活动。
超 市共出售N种不同的商品,编号为1…N。不同的物品对Bob来说有不同的价值,第i种物品每一个的价值为Wi。而每种商品的售价也不相同,第i种物品的单 价为Ci元。同一种商品可以买多个。超市经理为了避免某些商品被一抢而光,决定每种商品每位顾客最多只能买Li个。现在,Bob共有M元,他想知道在花费 不超过M元的情况下,能买到的商品价值和最大为多少?

Input

第1行两个整数N和M,分别表示商品的种数与Bob现有的钱数。
接下来N行每行为三个整数Ci,Wi,Li,分别表示第i种商品的单价,单个的价值,最多可购买的件数。

Output

输出只有一行,为Bob能买到的商品最大价值和。

Sample Input

5 30
3 1 3
1 4 1
8 10 3
4 7 2
2 2 4

Sample Output

42

Hint

20%的数据:N≤30,M≤10000,Li≤500;
70%的数据:N≤50,M≤500000,Li≤2000;
100%的数据:N≤50,M≤500000,Li≤500000;
----------------------------------------------------------------
Code:
#include<cstdio>
#include<algorithm>
using namespace std;

int n,m,l[55],c[55],w[55],f[2][500005],q[500005];

int main(){
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++){
    scanf("%d %d %d",&c[i],&w[i],&l[i]);
}
for(int i=1;i<=n;i++){
    int now=i%2,last;
    last=now^1;
    for(int j=0;j<c[i];j++){
        int Rear=1,Front=1;
        q[1]=0;
        for(int k=0;k*c[i]+j<=m;k++){
            while(Front!=Rear && k-q[Front]>l[i])Front++;
            f[now][k*c[i]+j]=max(f[last][k*c[i]+j],f[last][q[Front]*c[i]+j]+w[i]*(k-q[Front]));
            while(Front<=Rear && f[last][q[Rear]*c[i]+j]+w[i]*(k-q[Rear])<=f[last][k*c[i]+j])Rear--;
            q[++Rear]=k;
        }
    }
}
printf("%d\n",f[n%2][m]);
return 0;
}

 

Category: OI | Tags: OI
10
14
2015
3

BZOJ USACO刷水记

计划做一做BZOJ上的USACO Silver……正好可以水一水刷题量了,提高代码能力

其实这是模仿jiry_2做的……

现在刷了多少题(以BZOJ搜索silver和资格赛关键词得到的题目作为基准)

8

我懒得写一句话题解了……为了文章量,每一道大水题我都会发一个题解。

Category: 随笔 | Tags: OI
10
13
2015
0

[BZOJ1787&1832] [AHOI2008] Meet 紧急集合 && 聚会

颓废了2个晚上,总算水掉了这道题……

这题我们使用倍增LCA可以解决。

每次三个点找两点间LCA,相同的LCA取另一个就可以了。

我没有使用读入优化,如果用了速度会更快吧……

#include<cstdio>

int n,m,h[500005],en,fa[500005][20],deep[500005],flg[500005];

struct Edge{
int b,next;
}e[1000005];

void add(int sa,int sb){
e[++en].b=sb;
e[en].next=h[sa];
h[sa]=en;
}

void Yuchuli(int u){
flg[u]=1;
for(int i=h[u];i;i=e[i].next){
    int v=e[i].b;
    if(!flg[v]){
        deep[v]=deep[u]+1;
        fa[v][0]=u;
        Yuchuli(v);
    }
}
}

void Move(int &u,int H){
for(int i=18;i>=0;i--){
    if(deep[fa[u][i]]>=H){
        u=fa[u][i];
    }
}
}

int LCA(int u,int v){
int now=0;
if(deep[u]!=deep[v]){if(deep[u]>deep[v])Move(u,deep[v]);else Move(v,deep[u]);}
if(u==v){return u;}
for(int i=18;i>=0;i--){
    if(fa[u][i]!=fa[v][i]){
        u=fa[u][i];
        v=fa[v][i];
    }
}
return fa[u][0];
}

int GetCost(int u,int v){
int w=LCA(u,v);
return deep[u]+deep[v]-2*deep[w];
}

int main(){
freopen("1787.in","r",stdin);
freopen("1787.out","w",stdout);
scanf("%d %d",&n,&m);
for(int i=1;i<n;i++){
    int sa,sb;
    scanf("%d %d",&sa,&sb);
    add(sa,sb);
    add(sb,sa);
}
Yuchuli(1);
fa[1][0]=1;
for(int j=1;j<=18;j++){
    for(int i=1;i<=n;i++){
        fa[i][j]=fa[fa[i][j-1]][j-1];
    }
}
while(m--){
    int sa,sb,sc;
    scanf("%d %d %d",&sa,&sb,&sc);
    int FineLCA,LCA1=LCA(sa,sb),LCA2=LCA(sa,sc),LCA3=LCA(sb,sc);
    if(LCA1==LCA2)FineLCA=LCA3;
    else if(LCA3==LCA2)FineLCA=LCA1;
    else FineLCA=LCA2;
    printf("%d %d\n",FineLCA,GetCost(FineLCA,sa)+GetCost(FineLCA,sb)+GetCost(FineLCA,sc));
}
return 0;
}

upd 2016.6.2

今天学习了Tarjan求LCA,用这个题练习一下

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

const int N=500005,INF=2100000000;

int n,m,h[N],en,f[N],vis[N],dep[N],anc[N];

struct Edge{
int b,next;
}e[N<<1];

struct List{
int v,par;
List *next;
List(){next=NULL;par=0;}
List(int _v,List *_next){v=_v;next=_next;par=0;}
}*Lis[N];

List *AddList(int u,int v){
List *node=new List(v,Lis[u]);
Lis[u]=node;
return node;
}

struct Query{
int u,v,w;
List *id11,*id12,*id21,*id22,*id31,*id32;
Query(){}
Query(int _u,int _v,int _w){u=_u;v=_v;w=_w;}
}Que[N];

void AddEdge(int sa,int sb){
e[++en].b=sb;
e[en].next=h[sa];
h[sa]=en;
}

int Find(int x){return x==f[x]?x:f[x]=Find(f[x]);}
int Abs(int x){return x>0?x:-x;}
int GetCost(int u,int v,int w){return dep[u]+dep[v]-2*dep[w];}

void Tarjan(int u,int fa){
f[u]=u;
dep[u]=dep[fa]+1;
for(int i=h[u];i;i=e[i].next){
	int v=e[i].b;
	if(!f[v]){Tarjan(v,u);f[v]=u;}
}
for(List *I=Lis[u];I;I=I->next){
    int v=I->v;
    if(f[v])I->par=Find(v);
}
}

int main(){
freopen("1787.in","r",stdin);
freopen("1787.out","w",stdout);
scanf("%d %d",&n,&m);
for(int i=1;i<n;i++){
	int u,v;
	scanf("%d %d",&u,&v);
	AddEdge(u,v);AddEdge(v,u);
}
for(int i=1;i<=m;i++){
	scanf("%d %d %d",&Que[i].u,&Que[i].v,&Que[i].w);
	Que[i].id11=AddList(Que[i].u,Que[i].v);
	Que[i].id21=AddList(Que[i].u,Que[i].w);
	Que[i].id31=AddList(Que[i].v,Que[i].w);
	Que[i].id12=AddList(Que[i].v,Que[i].u);
	Que[i].id22=AddList(Que[i].w,Que[i].u);
	Que[i].id32=AddList(Que[i].w,Que[i].v);
}
Tarjan(1,1);
for(int i=1;i<=m;i++){
    int LCA1=max(Que[i].id11->par,Que[i].id12->par);
    int LCA2=max(Que[i].id21->par,Que[i].id22->par);
    int LCA3=max(Que[i].id31->par,Que[i].id32->par);
    int Cost=GetCost(LCA1,Que[i].u,LCA1)+GetCost(LCA1,Que[i].v,LCA1)+GetCost(LCA1,Que[i].w,LCA2);
    if(LCA1==LCA2){Cost=GetCost(LCA3,Que[i].u,LCA2)+GetCost(LCA3,Que[i].v,LCA3)+GetCost(LCA3,Que[i].w,LCA3);LCA1=LCA3;}
    else if(LCA1==LCA3){Cost=GetCost(LCA2,Que[i].u,LCA2)+GetCost(LCA2,Que[i].v,LCA1)+GetCost(LCA2,Que[i].w,LCA2);LCA1=LCA2;}
	printf("%d %d\n",LCA1,Cost);
}
return 0;
}
Category: BZOJ | Tags: OI bzoj
10
10
2015
0

[BZOJ1007] [HNOI2008] 水平可见直线

想了一下,又看看黄大神的blog,然后就水掉了这题……

具体请看hzwer's blog:点击此处

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;

int n,flg[50005],ST;

struct Node{
double a,b;
int i;
}a[50005],s[50005];

int cmp(Node sa,Node sb){
if(fabs(sa.a-sb.a)<=0.0000001)return sa.b<sb.b;
return sa.a<sb.a;
}

double SetX(Node x,Node y){
return (y.b-x.b)/(x.a-y.a);
}

void Insert(int x){
while(ST){
    if(fabs(s[ST].a-a[x].a)<=0.0000001)ST--;
    else if(ST>1 && SetX(a[x],s[ST-1])<=SetX(s[ST],s[ST-1])){
        ST--;
    }
    else break;
}
s[++ST]=a[x];
}

int main(){
freopen("1007.in","r",stdin);
freopen("1007.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++){
    scanf("%lf %lf",&a[i].a,&a[i].b);
    a[i].i=i;
}
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++)Insert(i);
for(int i=1;i<=ST;i++)flg[s[i].i]=1;
for(int i=1;i<=n;i++)if(flg[i])printf("%d ",i);
return 0;
}
Category: BZOJ | Tags: OI
10
9
2015
0

[BZOJ1968] [Ahoi2005] COMMON 约数研究

喜闻乐见的良心大水题……(这种题居然放在bzoj上)

以下是代码,不用解释了吧

#include<cstdio>

int n,ans=0;
int main(){
freopen("1968.in","r",stdin);
freopen("1968.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)ans+=n/i;
printf("%d\n",ans);
return 0;
}
Category: BZOJ | Tags: OI
10
4
2015
0

[BZOJ1592] [Usaco2008 Feb] Making the Grade 路面修整

嗯……这题是做两遍dp,设f[i][j]为前i个点的路面当高度为j(已经离散化)后所能付出的最小代价,则状态转移方程为:

f[i][j]=min(f[i][j-1],f[i-1][j]+abs(j-a[i]))

我作死用了滚动数组……

#include<cstdio>
#include<algorithm>
using namespace std;

int n,a[2005],f[2][2005],g[2][2005],b[2005];

int absd(int h){
return h>0?h:-h;
}

int cmp(int sa,int sb){
return sa>sb;
}

int main(){
freopen("1592.in","r",stdin);
freopen("1592.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++){
    scanf("%d",&a[i]);
    b[i]=a[i];
}
sort(b+1,b+n+1);
f[1][0]=f[0][0]=2147483647;
for(int i=1;i<=n;i++){
    int now=i%2,pre;
    pre=now^1;
    for(int j=1;j<=n;j++){
        f[now][j]=min(f[now][j-1],f[pre][j]+absd(b[j]-a[i]));
    }
}
g[0][0]=g[1][0]=2147483647;
for(int i=1;i<=n;i++){
    int now=i%2,pre;
    pre=now^1;
    for(int j=1;j<=n;j++){
        g[now][j]=min(g[now][j-1],g[pre][j]+absd(b[n+1-j]-a[i]));
    }
}
printf("%d\n",min(g[n%2][n],f[n%2][n]));
return 0;
}
Category: BZOJ | Tags: OI
9
17
2015
0

[BZOJ2428] [HAOI2006] 均分数据

新知识get:模拟退火

设置一个温度T,T越小越不随机

然后做个几万遍就可以了。

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
 
double ans=2147483647,average=0;
int n,m,a[10005],sum[10005],zu[10005];
 
void Fire(){
double T=10000,nowans=0;
memset(sum,0,sizeof(sum));
for(int i=1;i<=n;i++){
    zu[i]=rand()%m+1;
    sum[zu[i]]+=a[i];
}
for(int i=1;i<=m;i++){
    nowans+=(sum[i]-average)*(sum[i]-average);
}
while(T>0.1){
    T*=0.9;
    int Nx,Ny,R=rand()%n+1;
    Nx=zu[R];
    if(T>500){
        int sa=2147483647,sb;
        for(int i=1;i<=m;i++){
            if(sa>sum[i]){
                sa=sum[i];
                sb=i;
            }
        }
        Ny=sb;
    }
    else Ny=rand()%m+1;
    if(Nx==Ny)continue;
    double lastans=nowans;
    nowans-=(sum[Nx]-average)*(sum[Nx]-average);
    nowans-=(sum[Ny]-average)*(sum[Ny]-average);
    sum[Nx]-=a[R];
    sum[Ny]+=a[R];
    nowans+=(sum[Nx]-average)*(sum[Nx]-average);
    nowans+=(sum[Ny]-average)*(sum[Ny]-average);
    if(nowans<=lastans){zu[R]=Ny;}
    else {
        if(rand()%10000>T){
            sum[Nx]+=a[R];
            sum[Ny]-=a[R];
            nowans=lastans;
        }
        else {
            zu[R]=Ny;
        }
    }
}
ans=min(nowans,ans);
}
 
int main(){
srand(19990720);
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++){
    scanf("%d",&a[i]);
    average+=a[i];
}
average/=m;
for(int i=1;i<=10000;i++){
    Fire();
}
printf("%.2lf\n",sqrt(ans/m));
return 0;
}
Category: BZOJ | Tags: OI
9
5
2015
0

[BZOJ1002] [FJOI2007] 轮状病毒

公式: f[i]=3*f[i-1]-f[i-2]+2

我自己是用了三个变量滚动。需要写一个高精度。

#include<cstdio>
#include<cstring>
 
struct Num{
int n,s[100005];
}f1,f2,f3;
 
int n;
 
void Do(){
f3.n=f2.n;
memset(f3.s,0,sizeof(f3.s));
for(int i=0;i<f2.n;i++){
    f3.s[i]+=f2.s[i]*3;
    if(f3.s[i]>9){
        f3.s[i+1]+=f3.s[i]/10;
        f3.s[i]%=10;
    }
}
if(f3.s[f3.n]>0)f3.n++;
//printf("CTest2:%d%d\n",f2.s[0],f2.s[1]);
//printf("CTest3:%d%d\n",f3.s[0],f3.s[1]);
//printf("Test1:%d%d\n",f1.s[0],f1.s[1]);
f3.s[0]+=2-f1.s[0];
//printf("Test3:%d%d\n",f3.s[0],f3.s[1]);
if(f3.s[0]>9){
    f3.s[1]+=f3.s[0]/10;
    //printf("Test:%d%d\n",f3.s[0],f3.s[1]);
    f3.s[0]%=10;
}
else if(f3.s[0]<0){
    f3.s[1]--;
    f3.s[0]+=10;
}
for(int i=1;i<f1.n;i++){
    f3.s[i]-=f1.s[i];
    if(f3.s[i]<0){
        f3.s[i+1]--;
        f3.s[i]+=10;
    }
}
if(f3.s[f3.n-1]==0)f3.n--;
}
 
void Copy(){
f1.n=f2.n;
for(int i=0;i<f2.n;i++){f1.s[i]=f2.s[i];}
f2.n=f3.n;
for(int i=0;i<f3.n;i++){f2.s[i]=f3.s[i];}
}
 
int main(){
freopen("1002.in","r",stdin);
freopen("1002.out","w",stdout);
scanf("%d",&n);
if(n==1){printf("1\n");return 0;}
if(n==2){printf("5\n");return 0;}
f1.n=1;
f1.s[0]=1;
f2.n=1;
f2.s[0]=5;
n-=2;
while(n--){
    Do();
    Copy();
}
for(int i=f2.n-1;i>=0;i--){
    printf("%d",f2.s[i]);
}
putchar('\n');
return 0;
}
Category: BZOJ | Tags: OI

Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com