【NOIP2015D2】 解题报告

来源:互联网 发布:香港专业教育学院 知乎 编辑:程序博客网 时间:2024/05/16 17:57

这次模拟考试订正历程很悲催……

Solution

T1:很经典的二分答案,直接切掉
T2:听说过是DP,考试时先写了一个dfs,发现要记录前一个有没有选来看后面的是否连在一起,f[i][j][k][sta]表示A数组前i个,B数组前j个,分成k段,最后两个是否匹配的方案数,一开始忘记选了也可以分为2段,总的方程就是比较a[i+1]和b[j+1],若不同,只能推到f[i+1][j][k][0],若相同,a[i+1]可以不选,就是f[i+1][j][k][0],选,但是自成一段,a[i+1][j+1][k+1][1],或者与前面的合并,但是a[i]得选,f[i+1][j+1][k][1]。
T3:其实一开始不会,一直想不出去掉一条边后怎么计算所有的路径并统计,只会暴力的50分,后来看了题解……发现一开始思路错了,应该想二分,去判断比较简单,就把所有的不符合的路径拿出来,然后记录,然后取所有路径的交集中最长的一条边,看不符合条件的最长的一条路径是否符合即可,思路还算简单。实现上要用树上差分,就是对于路径(u,v),tmp[u]++,tmp[v]++,tmp[lca(u,v)]-=2,tmp[i]表示从i开始向上到根的路径有多少,统计的时候自底向上计算,实现是DFS,先算儿子,父亲tmp+=儿子tmp,记录tmp=cnt的节点,最后判断即可。

订正时遇到的问题:一直WA,吐血的那种,最后发现有些代码没有dfs(v,u),有些代码lca的k只到2(调试时改的),我去。

CODE

T1:

#include<bits/stdc++.h>using namespace std;const int MAXN=50010;int a[MAXN],L,n,m;bool check(int k){    int last=0,cnt=0;    for (int i=1;i<=n;i++)        if (a[i]-last<k) cnt++;        else last=a[i];    if (L-last<k) cnt++;    return cnt<=m;   }int main(){    scanf("%d%d%d",&L,&n,&m);    for (int i=1;i<=n;i++)        scanf("%d",&a[i]);    int l=0,r=L;    while (l<r)    {        int mid=(l+r+1)>>1;        if (check(mid)) l=mid;        else r=mid-1;           }    printf("%d\n",l);   }

T2:

#include<bits/stdc++.h>using namespace std;#define MOD 1000000007char a[1010],b[210];int f[2][205][2][205],n,m,K,ans,now;int main(){    scanf("%d%d%d",&n,&m,&K);    scanf("%s",a+1);    scanf("%s",b+1);    n=strlen(a+1); m=strlen(b+1);    f[0][0][0][0]=1; now=0;    for (int i=0;i<n;i++)    {        for (int j=0;j<=m;j++)            for (int k=0;k<=K;k++)                for (int sta=0;sta<=1;sta++)                {                    int p=f[now][j][sta][k];                    if (!p) continue;                    f[1-now][j][0][k]=(f[1-now][j][0][k]+p)%MOD;                    if (j<m && a[i+1]==b[j+1])                     {                        if (sta) f[1-now][j+1][1][k]=(f[1-now][j+1][1][k]+p)%MOD;                        f[1-now][j+1][1][k+1]=(f[1-now][j+1][1][k+1]+p)%MOD;                    }                    f[now][j][sta][k]=0;                }        now=1-now;    }    ans=(f[now][m][0][K]+f[now][m][1][K])%MOD;    printf("%d\n",ans);    return 0;}

T3:

#include<bits/stdc++.h>using namespace std;const int MAXN=300010,MAXM=300010;int Head[MAXN],tot,n,m,maxdeep,cnt,limit,ans;int fa[MAXN],f[21][MAXN],deep[MAXN],dis[MAXN],tmp[MAXN];struct Edge{    int v,d,next;}edge[MAXN*2];struct node{    int u,v,d,lca;}e[MAXM];void addedge(int x,int y,int z){    edge[++tot]=(Edge){y,z,Head[x]};    Head[x]=tot;}void dfs_pre(int u,int pre){    maxdeep=max(maxdeep,deep[u]);    for (int i=Head[u];i;i=edge[i].next)    {        int v=edge[i].v,d=edge[i].d;        if (v==pre) continue;        fa[v]=u; deep[v]=deep[u]+1; dis[v]=dis[u]+d;        dfs_pre(v,u);    }   }int query_lca(int u,int v){    if (deep[u]<deep[v]) swap(u,v);    int step=deep[u]-deep[v];    for (int k=0;k<=20;k++)        if (step & (1<<k)) u=f[k][u];    for (int k=20;k>=0;k--)        if (f[k][u]!=f[k][v])             u=f[k][u],v=f[k][v];    return u==v?u:fa[u];    }void calc_lca(){    memset(f,-1,sizeof(f));    int k=log(n)/log(2);    for (int i=1;i<=n;i++) f[0][i]=fa[i];    for (int j=1;j<=k;j++)        for (int i=1;i<=n;i++)            if (f[j-1][i]!=-1) f[j][i]=f[j-1][f[j-1][i]];    for (int i=1;i<=m;i++)    {        int u=e[i].u,v=e[i].v;        e[i].lca=query_lca(u,v);        e[i].d=dis[u]+dis[v]-2*dis[e[i].lca];    }}void init(){    scanf("%d%d",&n,&m);    for (int i=1;i<n;i++)    {        int x,y,z;        scanf("%d%d%d",&x,&y,&z);        addedge(x,y,z);        addedge(y,x,z);    }    for (int i=1;i<=m;i++)        scanf("%d%d",&e[i].u,&e[i].v),e[i].d=0;    fa[1]=-1; deep[1]=1; dis[1]=0;    dfs_pre(1,1);     calc_lca();}int dfs(int u,int pre){    for (int i=Head[u];i;i=edge[i].next)    {        int v=edge[i].v,d=edge[i].d;        if (v==pre) continue;        dfs(v,u);        if (tmp[v]==cnt) ans=max(ans,d);        tmp[u]+=tmp[v];    }    return ans;}bool check(int mid){    memset(tmp,0,sizeof(tmp));    cnt=0,limit=0;    for (int i=1;i<=m;i++)        if (e[i].d>mid)        {            cnt++;            tmp[e[i].u]++;            tmp[e[i].v]++;            tmp[e[i].lca]-=2;            limit=max(limit,e[i].d-mid);        }    if (!cnt) return true;    ans=-1; dfs(1,0);    return ans>=limit;  }void solve(){    int l=0,r=300000000;    while (l<r)    {        int mid=(l+r)>>1;        if (check(mid)) r=mid;        else l=mid+1;           }    printf("%d\n",r);   }int main(){    //freopen("transport.in","r",stdin);    //freopen("transprot.out","w",stdout);    init();    solve();        return 0;}
原创粉丝点击