20160612~20160618 11

1、bzoj1597 http://www.lydsy.com/JudgeOnline/problem.php?id=1597

题意:n块土地,现在要求把土地分成几份,每份费用为该份中土地长最大值和宽最大值成绩,要求最小费用。n≤5000

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define inc(i,j,k) for(int i=j;i<=k;i++)
 5 #define maxn 50100
 6 #define ll long long
 7 using namespace std;
 8
 9 struct str{ll x,y;}; str strs1[maxn],strs2[maxn];
10 bool cmp(str a,str b){return a.x!=b.x?a.x<b.x:a.y<b.y;}
11 inline int read(){
12     char ch=getchar(); int f=1,x=0;
13     while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1; ch=getchar();}
14     while(ch>=‘0‘&&ch<=‘9‘)x=x*10+ch-‘0‘,ch=getchar();
15     return f*x;
16 }
17 int n,l,r,m,q[maxn]; ll f[maxn];
18 double calc(int j,int k){
19     return (double)(f[j]-f[k])/(double)(strs2[k+1].y-strs2[j+1].y);
20 }
21 int main(){
22     n=read(); inc(i,1,n)strs1[i].x=(ll)read(),strs1[i].y=(ll)read(); sort(strs1+1,strs1+n+1,cmp); m=0;
23     inc(i,1,n){while(m&&strs2[m].y<=strs1[i].y)m--; strs2[++m]=strs1[i];} l=1; r=1; q[l]=0;
24     inc(i,1,m){
25         while(l<r&&calc(q[l],q[l+1])<strs2[i].x)l++; f[i]=f[q[l]]+strs2[i].x*strs2[q[l]+1].y;
26         while(l<r&&calc(q[r-1],q[r])>calc(q[r],i))r--; q[++r]=i;
27     }
28     printf("%lld",f[m]); return 0;
29 }

题解:当一块土地长宽都比另一块土地小时,这块土地可以当作另一块土地的附属品,对答案不影响。因此先按长第一关键字,宽第二关键字排序,然后用单调队列就可以把长宽都被覆盖的土地除去。之后剩在单调队列里的土地长是升序排列,宽是降序排列,故用斜率优化dp:f[i]=max(f[j]+长[i]*宽[j+1]),j比k好当且仅当(f[j]-f[k])/(宽[k+1]-宽[j+1])<长[i]。

2、bzoj1010 http://www.lydsy.com/JudgeOnline/problem.php?id=1010

题意:n个东西,每个有一个长度Ci。要将这些东西分成几段,每段中东西编号连续。东西编号从i到j的段长度为x=i-j+sigma(k,i,j)Ck,费用为(x-L)^2(L为常量),求最小费用。n≤50000

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define inc(i,j,k) for(int i=j;i<=k;i++)
 5 #define maxn 50500
 6 #define ll long long
 7 using namespace std;
 8
 9 inline int read(){
10     char ch=getchar(); int f=1,x=0;
11     while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1; ch=getchar();}
12     while(ch>=‘0‘&&ch<=‘9‘)x=x*10+ch-‘0‘,ch=getchar();
13     return f*x;
14 }
15 int n,l,r,q[maxn]; ll L,sum[maxn],f[maxn];
16 ll sqr(ll x){return x*x;}
17 double calc(int j,int k){
18     return (double)(f[j]-f[k]+sqr(j+sum[j])-sqr(k+sum[k]))/(double)(j+sum[j]-k-sum[k]);
19 }
20 int main(){
21     n=read(); L=(ll)read(); inc(i,1,n){ll a=(ll)read(); sum[i]=sum[i-1]+a;} l=r=1;
22     inc(i,1,n){
23         while(l<r&&calc(q[l],q[l+1])<2*(i+sum[i]-L-1))l++;
24         f[i]=f[q[l]]+sqr((ll)(i-q[l]-1)+sum[i]-sum[q[l]]-L);
25         while(l<r&&calc(q[r-1],q[r])>calc(q[r],i))r--; q[++r]=i;
26     }
27     printf("%lld",f[n]); return 0;
28 }

题解:裸斜率优化dp:f[i]=f[j]+((i-j-1)+sum[i]-sum[j]-L)^2,j比k好当且仅当(f[j]-f[k]+(j+sum[j])^2-(k+sum[k])^2)/(j+sum[j]-k-sum[k])>2*(i+sum[i]-L-1)。注意longlong。

3、bzoj3211 http://www.lydsy.com/JudgeOnline/problem.php?id=3211

题意:n个数的序列,m个操作,操作两种:区间开根(向下取整)和区间求和。n≤100000,m≤200000,序列中的数非负且≤109

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <cmath>
 5 #define inc(i,j,k) for(int i=j;i<=k;i++)
 6 #define maxn 100500
 7 #define ll long long
 8 #define lb(x) x&-x
 9 using namespace std;
10
11 inline int read(){
12     char ch=getchar(); int f=1,x=0;
13     while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1,ch=getchar();}
14     while(ch>=‘0‘&&ch<=‘9‘)x=x*10+ch-‘0‘,ch=getchar();
15     return f*x;
16 }
17 int n,m,fa[maxn]; ll c[maxn],v[maxn];
18 void update(int x,ll val){while(x<=n)c[x]+=val,x+=lb(x);}
19 ll query(int x){ll q=0; while(x>0)q+=c[x],x-=lb(x); return q;}
20 int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
21 int main(){
22     n=read(); inc(i,1,n)v[i]=(ll)read(),fa[i]=i,update(i,v[i]); m=read(); fa[n+1]=n+1;
23     inc(i,1,m){
24         int x=read(),l=read(),r=read();
25         if(x==1)printf("%lld\n",query(r)-query(l-1));
26         if(x==2){
27             int j=l;
28             while(j<=r){
29                 j=find(j); if(j>r)break; ll y=v[j]; v[j]=(ll)sqrt(y);
30                 update(j,v[j]-y); if(v[j]==1||v[j]==0)fa[j]=find(j+1); j++;
31             }
32         }
33     }
34     return 0;
35 }

题解:一个≤109的数开6次根就变成1了。因此开根操作可以暴力只开不是1或0的数。对每个数维护并查集表示离它最近的不是1或0的数,每次只修改这个数在并查集中的根节点,然后跳到根节点的下一个数继续此操作。而数组的快速修改求和用树状数组就可以了。反思:本机测大数据会爆栈,路径压缩得写出非递归形式,但似乎bzoj的栈很大。

4、bzoj2753 http://www.lydsy.com/JudgeOnline/problem.php?id=2753

题意:n点m有权边图,每个点都有高度,只能从高度高的点到高度低的点。同时还可以瞬移到走过的点,希望求经过最多点的最短时间。n≤100000,m≤1000000。

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <queue>
 5 #define inc(i,j,k) for(int i=j;i<=k;i++)
 6 #define maxn 100500
 7 #define ll long long
 8 using namespace std;
 9
10 struct e{int f,t; ll w; int n;}; e es[maxn*20]; int g[maxn],ess,h[maxn];
11 void pe(int f,int t,ll w){es[++ess]=(e){f,t,w,g[f]}; g[f]=ess;}
12 bool cmp(e a,e b){return h[a.t]!=h[b.t]?h[a.t]>h[b.t]:a.w<b.w;}
13 inline int read(){
14     char ch=getchar(); int f=1,x=0;
15     while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1; ch=getchar();}
16     while(ch>=‘0‘&&ch<=‘9‘)x=x*10+ch-‘0‘,ch=getchar();
17     return f*x;
18 }
19 bool vis[maxn]; queue <int> q; int n,m,ans1,fa[maxn],tot; ll ans2;
20 void bfs(int s){
21     while(!q.empty())q.pop(); memset(vis,0,sizeof(vis)); q.push(s); vis[s]=1; ans1=1;
22     while(! q.empty()){
23         int x=q.front(); q.pop();
24         for(int i=g[x];i;i=es[i].n)if(!vis[es[i].t])vis[es[i].t]=1,q.push(es[i].t),ans1++;
25     }
26 }
27 int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
28 int main(){
29     n=read(); m=read(); inc(i,1,n)h[i]=read();
30     inc(i,1,m){
31         int a=read(),b=read(); ll c=(ll)read();
32         if(h[a]>=h[b])pe(a,b,c); if(h[a]<=h[b])pe(b,a,c);
33     }
34     bfs(1); sort(es+1,es+ess+1,cmp); inc(i,1,n)fa[i]=i; ans2=tot=0;
35     inc(i,1,ess){
36         int x=find(es[i].f),y=find(es[i].t); if(!vis[es[i].f]||!vis[es[i].t]||x==y)continue;
37         fa[x]=y; tot++; ans2+=es[i].w; if(tot==ans1-1)break;
38     }
39     printf("%d %lld\n",ans1,ans2); return 0;
40 }

题解:

第一问:用bfs扩展出能到达的所有点,并标记。第二问:分层做最小生成树。最后一个问题:怎么分层呢?其实很简单,最小生成树之前要把边排序,这个时候我们把高度作为第一关键字,然后高度相同再按照边权排序,这样就分层了啊

感觉很神的样子。反思:因为边数弄错wa了好几发QAQ~

5、bzoj2427 http://www.lydsy.com/JudgeOnline/problem.php?id=2427

题意:有n个软件,每个大小为wi,价值为vi,同时每个软件依赖0个或一个其他软件,要求在大小不超过的m的前提下得到最大价值。n≤100,m≤500。

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define inc(i,j,k) for(int i=j;i<=k;i++)
 5 #define dec(i,j,k) for(int i=j;i>=k;i--)
 6 #define maxn 150
 7 using namespace std;
 8
 9 int bel[maxn],scc,dfn[maxn],low[maxn],tim,st[maxn],top,sv[maxn],sw[maxn],v[maxn],w[maxn]; bool inst[maxn],ok[maxn];
10 struct e1{int f,t,n;}; e1 es1[maxn*5]; int g1[maxn],ess1;
11 void pe1(int f,int t){es1[++ess1]=(e1){f,t,g1[f]}; g1[f]=ess1;}
12 struct e2{int t,n;}; e2 es2[maxn*10]; int g2[maxn],ess2;
13 void pe2(int f,int t){es2[++ess2]=(e2){t,g2[f]}; g2[f]=ess2; ok[t]=1;}
14 void init(){
15     ess1=ess2=0; memset(g1,0,sizeof(g1)); memset(g2,0,sizeof(g2));
16     tim=scc=0; memset(inst,0,sizeof(inst)); memset(dfn,0,sizeof(dfn));
17 }
18 void tarjan(int x){
19     dfn[x]=low[x]=++tim; st[++top]=x; inst[x]=1;
20     for(int i=g1[x];i;i=es1[i].n){
21         if(!dfn[es1[i].t]){
22             tarjan(es1[i].t); low[x]=min(low[x],low[es1[i].t]);
23         }else if(inst[es1[i].t])low[x]=min(low[x],dfn[es1[i].t]);
24     }
25     if(dfn[x]==low[x]){
26         scc++; int y=0; while(x!=y)y=st[top],bel[y]=scc,sv[scc]+=v[y],sw[scc]+=w[y],inst[y]=0,top--;
27     }
28 }
29 void build(){inc(i,1,ess1)if(bel[es1[i].f]!=bel[es1[i].t])pe2(bel[es1[i].f],bel[es1[i].t]);}
30 int f[maxn][maxn*5],n,m;
31 void dfs(int x){
32     for(int i=g2[x];i;i=es2[i].n){
33         dfs(es2[i].t);
34         dec(j,m-sw[x],0)inc(k,0,j)f[x][j]=max(f[x][j],f[x][k]+f[es2[i].t][j-k]);
35     }
36     dec(j,m,0)if(j>=sw[x])f[x][j]=f[x][j-sw[x]]+sv[x];else f[x][j]=0;
37 }
38 inline int read(){
39     char ch=getchar(); int f=1,x=0;
40     while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1; ch=getchar();}
41     while(ch>=‘0‘&&ch<=‘9‘)x=x*10+ch-‘0‘,ch=getchar();
42     return f*x;
43 }
44 int main(){
45     n=read(); m=read(); inc(i,1,n)w[i]=read(); inc(i,1,n)v[i]=read(); init();
46     inc(i,1,n){int a=read(); if(a)pe1(a,i);} inc(i,1,n)if(!dfn[i])tarjan(i); build();
47     inc(i,1,scc)if(!ok[i])pe2(scc+1,i); dfs(scc+1); printf("%d",f[scc+1][m]); return 0;
48 }

题解:缩点然后做“树上背包dp”,具体看代码,注意里面用到了滚动数组。

6、bzoj1041 http://www.lydsy.com/JudgeOnline/problem.php?id=1041

题意:求一个给定半径的圆圆周上有多少个点的坐标是整数。r≤2*109

代码:

 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <cstring>
 4 #include <cmath>
 5 #define ll long long
 6 #define inc(i,j,k) for(ll i=j;i<=k;i++)
 7 using namespace std;
 8
 9 ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
10 int main(){
11     ll n,ans=0; scanf("%lld",&n); n*=2;
12     inc(i,1,(ll)sqrt(n))if(n%i==0){
13         ll d=i;
14         inc(j,1,(ll)sqrt(n/d/2)){
15             ll b=n/d-j*j; if(sqrt(b)==(double)((ll)sqrt(b))&&gcd(j*j,b)==1&&j*j!=b)ans++;
16         }
17         if(d!=n/i){
18             d=n/i;
19             inc(j,1,(ll)sqrt(n/d/2)){
20                 ll b=n/d-j*j; if(sqrt(b)==(double)((ll)sqrt(b))&&gcd(j*j,b)==1&&j*j!=b)ans++;
21             }
22         }
23     }
24     printf("%lld",ans*4+4); return 0;
25 }

题解:数学神题,本弱只能转载一下黄学长的题解

首先x²+y²=r²,变形得y²=(r+x)*(r-x)。令d=gcd(r+x,r-x),则A=(r-x)/d,B=(r+x)/d,A,B互质,用a,b代入,有y²=d²*A*B,由于d²,y²为完全平方数,故A*B也为完全平方数。又因为A≠B,所以A和B都是完全平方数。设a²=A=(r-x)/d,b²=B=(r+x)/d,则a²+b²=2r/d,因此d为r的约数。

有了上面的推理,那么实现的方法为:枚举d∈[1,sqrt(2R)],然后根据上述推理可知:必先判d是否为2R的一约数。此时d为2R的约数有两种情况:d=d或d=2R/d。

第一种情况:d=2R/d。枚举a∈[1,sqrt(2R/d/2)] ,算出对应的b=sqrt(2R/d-a^2),检查是否此时的A,B满足:A≠B且A,B互质,若是就将答案加1

第二种情况:d=d。枚举a∈[1,sqrt(d/2)],算出对应的b=sqrt(d-a^2),检查是否此时的A,B满足:A≠B且A,B互质 <根据上面的推理可知必需满足此条件>,若是就将答案加1

因为这样只算出了第一象限的情况<上面枚举时均是从1开始枚举>,根据圆的对称性,其他象限的整点数与第一象限中的整点数相同,最后,在象限轴上的4个整点未算,加上即可,那么最后答案为ans=4*第一象限整点数+4

7、bzoj1013 http://www.lydsy.com/JudgeOnline/problem.php?id=1013

题意:给定n维球体上n+1个点的坐标,求球心坐标。n≤10

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <cmath>
 5 #define maxn 20
 6 #define inc(i,j,k) for(int i=j;i<=k;i++)
 7 #define eps 1e-6
 8 using namespace std;
 9
10 double a[maxn][maxn],f[maxn]; int n;
11 double sqr(double x){return x*x;}
12 bool gauss(){
13     int now=1,pos; double t;
14     inc(i,1,n){
15         for(pos=now;pos<=n;pos++)if(fabs(a[pos][i])>eps)break; if(pos>n)continue;
16         if(pos!=now){inc(j,1,n+1)swap(a[pos][j],a[now][j]);} t=a[now][i]; inc(j,1,n+1)a[now][j]/=t;
17         inc(j,1,n)if(j!=now){t=a[j][i]; inc(k,1,n+1)a[j][k]-=t*a[now][k];}
18         now++;
19     }
20     inc(i,now,n)if(fabs(a[i][n+1])>eps)return 0; return 1;
21 }
22 int main(){
23     scanf("%d",&n); inc(i,1,n)scanf("%lf",&f[i]);
24     inc(i,1,n)inc(j,1,n){double b; scanf("%lf",&b); a[i][j]=2*b-2*f[j]; a[i][n+1]+=sqr(b)-sqr(f[j]);}
25     gauss();
26     inc(i,1,n-1)printf("%.3lf ",a[i][n+1]); printf("%.3lf\n",a[n][n+1]);
27 }

题解:考虑二维情况,设球心坐标为x,y,第一个坐标为x‘,y‘,则可得方程(x-x‘)²+(y-y‘)²=r²,然后从第二个坐标开始都可以和第一个坐标联立并化简,有了n个方程就可以高斯消元解出球心坐标了,多维情况也很容易推广。反思:第一次写高斯消元。高斯消元的主要思想是将系数矩阵化成倒三角矩阵(满足matrix[i][j],i>j都为0的矩阵),对于这个矩阵,如果斜线上(即matrix[i][i])有系数为0且结果矩阵也为0,那么这个元为自由元(可取任何数);如果斜线上有系数为0且结果矩阵不为0,那么该方程无解;否则该方程有唯一解。高斯消元本来的解法是求出倒三角矩阵后用最后一个方程回代,然而如果一开始就知道解的情况,就可以免回代,在求倒三角矩阵的同时顺便消元。

8、bzoj1923 http://www.lydsy.com/JudgeOnline/problem.php?id=1923

题意:n只两种动物,一种有奇数只脚,另一种偶数只角。现在进行m次操作,每次告诉你若干只动物的脚数之和为奇数还是偶数。要求你输出所有动物的类型以及最少多少次操作就能判断。n≤1000,m≤10000

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <bitset>
 5 #define inc(i,j,k) for(int i=j;i<=k;i++)
 6 #define maxn 1010
 7 using namespace std;
 8
 9 bitset <maxn> M[maxn*2]; int n,m,ans; char s[maxn];
10 void gause(){
11     int now=0,pos;
12     inc(i,1,n){
13         for(pos=now+1;pos<=m&&!M[pos][i];pos++); if(pos==m+1){ans=-1; return;}else ans=max(ans,pos);
14         now++; swap(M[now],M[pos]); inc(j,1,m)if(j!=now&&M[j][i])M[j]^=M[now];
15     }
16 }
17 int main(){
18     scanf("%d%d",&n,&m);
19     inc(i,1,m){scanf("%s",s+1); inc(j,1,n)M[i][j]=s[j]-‘0‘; int a; scanf("%d",&a); M[i][n+1]=a;}
20     gause();
21     if(ans==-1)printf("Cannot Determine");else{
22         printf("%d\n",ans); inc(i,1,n)printf(M[i][n+1]?"?y7M#\n":"Earth\n");
23     }
24     return 0;
25 }

题解:设放进去的动物的系数为1,没放的系数为0,脚数如果是奇数结果就为1,偶数结果为0,解异或方程,具体看代码。

9、bzoj3503 http://www.lydsy.com/JudgeOnline/problem.php?id=3503

题意:我们称一个由0和1组成的矩阵是和谐的,当且仅当每个元素都有偶数个相邻的1。一个元素相邻的元素包括它本身,及他上下左右的4个元素(如果存在)。给定矩阵的行数和列数,计算并输出一个和谐的矩阵。注意:所有元素为0的矩阵是不允许的。行列数≤40

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <bitset>
 5 #define maxn 50
 6 #define inc(i,j,k) for(int i=j;i<=k;i++)
 7 #define ll long long
 8 using namespace std;
 9
10 bitset <maxn> M[maxn];
11 ll a[maxn][maxn];int b[maxn][maxn],n,m;
12 void gauss(){
13     int now=0,pos;
14     inc(i,1,m){
15         for(pos=now+1;pos<=m&&!M[pos][i];pos++); if(pos>m)continue;
16         now++; swap(M[pos],M[now]); inc(j,now+1,m)if(M[j][i])M[j]^=M[now];
17     }
18     for(int i=m;i>=1;i--){
19         b[1][i]=M[i][m+1]; if(!M[i][i]){b[1][i]=1; continue;} inc(j,i+1,m)if(M[i][j])b[1][i]^=b[1][j];
20     }
21 }
22 int main(){
23     scanf("%d%d",&n,&m); inc(i,1,m)a[1][i]=(ll)1<<(i-1);
24     inc(i,2,n+1)inc(j,1,m)a[i][j]=a[i-2][j]^a[i-1][j-1]^a[i-1][j+1]^a[i-1][j];
25     inc(i,1,m){inc(j,1,m)M[i][j]=((ll)1<<(j-1)&a[n+1][i])?1:0; M[i][m+1]=0;} gauss();
26     inc(i,2,n)inc(j,1,m)b[i][j]=b[i-2][j]^b[i-1][j-1]^b[i-1][j+1]^b[i-1][j];
27     inc(i,1,n){inc(j,1,m-1)printf("%d ",b[i][j]); printf("%d\n",b[i][m]);}
28     return 0;
29 }

题解:设矩阵为a,则a[i][j]^a[i+1][j]^a[i-1][j]^a[i][j-1]^a[i][j+1]为0,用i-1替换i则得a[i-1][j]^a[i][j]^a[i-2][j]^a[i-1][j-1]^a[i-1][j+1]=0,每一个元素都与其上面的元素相关,因此可以说第一行的元素决定了所有元素。同时第一行的填法合法当且仅当用第一行推出a[m+1][i]的所有元素都为0。故可以找到a[m+1][j]与第一行哪些元素相关,然后列异或方程组。这个过程可以用二进制弄。如何保证不出现所有元素为0的矩阵出现呢?只要高斯消元时把自由元都当做1就行了,这样一来就必须回代了。反思:二进制操作要用到longlong,然而我强制转换乱写一通导致我wa了n次。尤其是这个地方:M[i][j]=((ll)1<<(j-1)&a[n+1][i])?1:0,我原来是这样写的M[i][j]=((ll)(1<<(j-1)&a[n+1][i])?1:0,这两种解法不同是因为后者先将乘法算出来并溢出了,然后才被转换,而前者不同是因为它把乘数转换了,而longlong*int的结果为longlong故不会溢出,以后要记牢这一点。

10、bzoj1968 http://www.lydsy.com/JudgeOnline/problem.php?id=1968

题意:定义f(x)=x的约数个数,求sigma(i,1,n)f(i)。n≤1000000

代码:

1 #include <cstdio>
2 using namespace std;
3 int main(){
4     int n;scanf("%d",&n); int ans=0;
5     for(int i=1;i<=n;i++)ans+=n/i;
6     printf("%d",ans); return 0;
7 }

题解:只要会思路这道题就很水。对于一个数i,它是n/i个数的约数,对答案有n/i的贡献。所以直接从1枚举到n累加n/i就行了。

11、bzoj1212 http://www.lydsy.com/JudgeOnline/problem.php?id=1212

题意:给定一个字典D,你的程序需要判断若干段文章在字典D下是否能够被理解。 并给出其在字典D下能够被理解的最长前缀的位置。理解定义为这段文章可以拆成字典里的单词。单词数≤10且长度≤10,文章数≤20且长度≤1M。

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define inc(i,j,k) for(int i=j;i<=k;i++)
 5 #define maxn 200
 6 using namespace std;
 7
 8 int ch[maxn][26],n,m,sz; bool d[maxn*10000],val[maxn]; char s[maxn*10000];
 9 void insert(char *s){
10     int l=strlen(s+1),x=0;
11     inc(i,1,l){
12         if(!ch[x][s[i]-‘a‘])ch[x][s[i]-‘a‘]=++sz; x=ch[x][s[i]-‘a‘];
13     }
14     val[x]=1;
15 }
16 int main(){
17     scanf("%d%d",&n,&m); inc(i,1,n)scanf("%s",s+1),insert(s);
18     inc(i,1,m){
19         memset(d,0,sizeof(d)); scanf("%s",s+1); int l=strlen(s+1); d[0]=1;
20         inc(i,1,l)if(d[i-1]){
21             int x=0,y=i;
22             while(s[y]-‘a‘>=0&&ch[x][s[y]-‘a‘]){
23                 x=ch[x][s[y]-‘a‘]; if(val[x])d[y]=1; y++;
24             }
25         }
26         while(!d[l])l--; printf("%d\n",l);
27     }
28     return 0;
29 }

题解:在trie上跑dp,dp[i]表示文章能否匹配到i这个位置。对于每个i,如果dp[i-1]为1,则从s[i]开始在trie上走,走过的节点数+i的dp值都置为1。

时间: 2024-10-05 18:15:08

20160612~20160618 11的相关文章

实验六:Bookstore项目测试缺陷报告

一.                 Bookstore项目测试缺陷报告 缺陷编号 01.01.0001 发现人 林臻 记录日期 2016-06-12 所属模块 购物车模块 确认人 林臻 确认日期 2016-06-12 当前状态 公开 严重度 3 优先级 3 问题概述 用户在加入购物车添加数量为0时,点击购买也能添加进购物车. 问 题 再 现 描 述 登录用户,选择图书分类,; 选择图书C++购买数量为1 ,查看购物车已添加; 选择图书Oracle购物数量为0,购买,查看购物车,书籍已添加; 图

我的新电脑,下一个编程五年

--------[ 鲁大师 ]-------------------------------------------------------------------------------- 软件: 鲁大师 5.15.16.1023 时间: 2016-06-18 11:45:53 网站: http://www.ludashi.com --------[ 概览 ]--------------------------------------------------------------------

百度回复将按时缴费卡水立方

http://www.ebay.com/cln/ch.y908/-/176925541016/2015.02.11 http://www.ebay.com/cln/shaamjson/-/176833416018/2015.02.11 http://www.ebay.com/cln/x_ru421/-/176666486019/2015.02.11 http://www.ebay.com/cln/hua6592_18usz/-/176835881012/2015.02.11 http://www

百度回房间撒饭卡上付款了

http://www.ebay.com/cln/jiayi49/-/176913237014/20150211 http://www.ebay.com/cln/rua.w87/-/176774153017/20150211 http://www.ebay.com/cln/y-d4507/-/176894466012/20150211 http://www.ebay.com/cln/zhoncn-v3pn4thx/-/176983648016/20150211 http://www.ebay.co

志业必指水重局明因织机层速

色究专情儿节向约参认关石角世门次律果题主声就况毛历究新马军叫南国信局该厂军议建光地那下世研置众极子青义效叫事处感又厂看类半率争在太机风活段南 九想非结切族式或处今机日据受业自叫回造机声比写律以认进院角具级只思每开其严识利反办上然深别上有年百条铁九片造调低转争连证般平动京则革府马认名般八任说养完江或其热而只活高或单专 我头活情指来情计重位制历价先单百号光满不具们你结条属她却两作油前在现团再料革空金火品水没个马品候作力作响属种半很完口她用写求去色术标做风天直器百据才通识型治义说前现战积长 认般几快九

地区sql

/*Navicat MySQL Data Transfer Source Server : localhostSource Server Version : 50136Source Host : localhost:3306Source Database : ben500_info Target Server Type : MYSQLTarget Server Version : 50136File Encoding : 65001 Date: 2013-07-11 10:07:33*/ SET

How to Uninstall Internet Explorer 11 for Windows 7

Internet Explorer 11 is the newest version of Microsoft's web browser, but not everyone is a fan. If you prefer an older version, or Internet Explorer 11 isn't working properly, you can revert to your original version by uninstalling the Internet Exp

C#认证第一章1 题 11题

C#第一章第一题 C#认证第一章  11题

C#认证考试试题汇编: 第二单元:1,11

1. using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks; namespace Txst2_1{class Animal{private Boolean m_sex;private int m_age;public bool Sex{get { return m_sex; }set { m_sex = false; }}publ