zoukankan      html  css  js  c++  java
  • NOI2015 迟来的测试,及时的总结

    因为耽误了网络同步赛,所以在将近一个月后进行了NOI的测试。

    DAY1

    T1程序自动分析

    题目大意:给定一些变量相等或不等的关系,判断是否矛盾。

    思路:离散化后,并查集维护一下。水水的开始。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxnode 200005
    using namespace std;
    struct use{
        int x1,x2,kk;
    }ask[maxnode]={0};
    int ai[maxnode]={0},fa[maxnode]={0};
    int cmp(const use &x,const use &y){return x.kk>y.kk;}
    int root(int x)
    {
        if (fa[x]!=x) fa[x]=root(fa[x]);
        return fa[x];
    }
    int main()
    {
        freopen("prog.in","r",stdin);
        freopen("prog.out","w",stdout);
        
        int t,i,j,n,m,siz,r1,r2;
        bool f;
        scanf("%d",&t);
        while(t)
        {
            scanf("%d",&n);ai[0]=0;
            for (i=1;i<=n;++i)
            {
                scanf("%d%d%d",&ask[i].x1,&ask[i].x2,&ask[i].kk);
                ai[++ai[0]]=ask[i].x1;
                ai[++ai[0]]=ask[i].x2;
            }
            sort(ai+1,ai+ai[0]+1);f=false;
            siz=unique(ai+1,ai+ai[0]+1)-ai-1;
            sort(ask+1,ask+n+1,cmp);
            for (i=1;i<=2*n;++i) fa[i]=i;
            for (i=1;i<=n;++i)
            {
                ask[i].x1=upper_bound(ai+1,ai+siz+1,ask[i].x1)-ai-1;
                ask[i].x2=upper_bound(ai+1,ai+siz+1,ask[i].x2)-ai-1;
                r1=root(ask[i].x1);r2=root(ask[i].x2);
                if (ask[i].kk==1)
                {
                    if (r1!=r2) 
                    {
                       if (i%3==0) swap(r1,r2);
                       fa[r1]=r2;
                    }
                }
                else
                {
                    if (r1==r2) 
                    {
                       f=true;break;
                    }
                }
            }
            if (f) printf("NO
    ");
            else printf("YES
    ");
            --t;
        }
        
        fclose(stdin);
        fclose(stdout);
    }
    View Code

    T2软件包管理器

    题目大意:给定一些软件之间的依赖关系(一棵树结构),安装时要把它到根上的都安装,卸载时要把它子树里的都卸载,求每一个操作改变的软件个数。

    思路:树链剖分——链和子树,线段树维护。水水的延续。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxnode 100005
    using namespace std;
    char ch[10];
    int tot=0,point[maxnode]={0},next[maxnode*2]={0},en[maxnode*2]={0},t[maxnode*4]={0},
        ri[maxnode]={0},delta[maxnode*4];
    bool visit[maxnode]={false};
    void add(int u,int v)
    {
        ++tot;next[tot]=point[u];point[u]=tot;en[tot]=v;
        ++tot;next[tot]=point[v];point[v]=tot;en[tot]=u;
    }
    void updata(int i){t[i]=t[i*2]+t[i*2+1];}
    void pushdown(int i,int l,int r)
    {
        int mid;
        mid=(l+r)/2;
        if (delta[i]>=0)
        {
            delta[i*2]=delta[i];
            t[i*2]=(delta[i*2]==1 ? (mid-l+1) : 0);
            delta[i*2+1]=delta[i];
            t[i*2+1]=(delta[i*2+1]==1 ? (r-mid) : 0);
            delta[i]=delta[0];
        }
    }
    int task(int i,int l,int r,int ll,int rr,int kk)
    {
        int mid,ans=0;
        if (ll<=l&&r<=rr) return (kk==1 ? t[i] : r-l+1-t[i]);
        pushdown(i,l,r);mid=(l+r)/2;
        if (ll<=mid) ans+=task(i*2,l,mid,ll,rr,kk);
        if (rr>mid) ans+=task(i*2+1,mid+1,r,ll,rr,kk);
        return ans;
    }
    void tch(int i,int l,int r,int ll,int rr,int kk)
    {
        int mid;
        if (ll<=l&&r<=rr)
        {
            delta[i]=kk;t[i]=(kk==1 ? (r-l+1) : 0);return;
        }
        mid=(l+r)/2;pushdown(i,l,r);
        if (ll<=mid) tch(i*2,l,mid,ll,rr,kk);
        if (rr>mid) tch(i*2+1,mid+1,r,ll,rr,kk);
        updata(i);
    }
    struct lp{
        int fa[maxnode],dep[maxnode],son[maxnode],siz[maxnode],tid[maxnode],top[maxnode];
        void dfs1(int u,int f,int depth)
        {
            int i,j,maxsiz=0;
            visit[u]=true;fa[u]=f;dep[u]=depth;
            siz[u]=1;son[u]=0;
            for (i=point[u];i;i=next[i])
            {
                if (!visit[j=en[i]])
                {
                    dfs1(j,u,depth+1);
                    siz[u]+=siz[j];
                    if (siz[j]>maxsiz)
                    {
                        maxsiz=siz[j];
                        son[u]=j;
                    }
                }
            }
        }
        void dfs2(int u,int anc)
        {
            int i,j;
            visit[u]=false;tid[u]=++tot;top[u]=anc;
            if (son[u]) dfs2(son[u],anc);
            for (i=point[u];i;i=next[i])
                if (visit[j=en[i]]) dfs2(j,j);
            ri[u]=tot;
        }
        int ins(int a,int b)
        {
            int ans=0;
            while(top[a]!=top[b])
            {
                if (dep[top[a]]<dep[top[b]]) swap(a,b);
                ans+=task(1,1,tot,tid[top[a]],tid[a],0);
                tch(1,1,tot,tid[top[a]],tid[a],1);
                a=fa[top[a]];
            }
            if (dep[a]>dep[b]) swap(a,b);
            ans+=task(1,1,tot,tid[a],tid[b],0);
            tch(1,1,tot,tid[a],tid[b],1);
            return ans;
        }
        int uni(int a)
        {
            int ans=0;
            ans=task(1,1,tot,tid[a],ri[a],1);
            tch(1,1,tot,tid[a],ri[a],0);
            return ans;
        }
    }tree;
    int main()
    {
        freopen("manager.in","r",stdin);
        freopen("manager.out","w",stdout);
        
        int n,q,i,j;
        scanf("%d",&n);
        for (i=2;i<=n;++i)
        {
            scanf("%d",&j);add(++j,i);
        }tot=0;
        tree.dfs1(1,0,1);tree.dfs2(1,1);
        memset(delta,128,sizeof(delta));
        scanf("%d",&q);
        for (i=1;i<=q;++i)
        {
            scanf("%*c%s%d",&ch,&j);
            if (ch[0]=='i')
            {
                printf("%d
    ",tree.ins(1,++j));
            }
            else
            {
                printf("%d
    ",tree.uni(++j));
            }
        }
        
        fclose(stdin);
        fclose(stdout);
    }
    View Code

    T3寿司晚宴

    题目大意:给定n-1种寿司,每个寿司编号2~n,求两个人去寿司的和谐方案的方案总数(一个方案称为和谐的当且仅当两人选择的寿司种类中两两编号互质。)

    思路:测试的时候,只会暴力打表,但是还因为常数赋值时没写LL就挂了。后来问了sunshine大爷才知道正解。首先我们知道一个数n最多只有一个大于根号n的质因子,所以我们可以对一个数构成两个特征值:第1个表示大于根n的质因子,第2个表示小于根n的质因数组成(用8位2进制数表示,根号500以内的质数只有8个)。对第一个特征值排序后对这个大质因数相同的一类数一起处理(如果这个特征值为1,则一个一个的处理)。设f[i][j]表示第一个人选i,第二个人选j(i、j表示质因数的选择情况),g[k][i][j]表示第k+1个人第一个人选i第二个人选j的方案数,在每一类数做之前都用f给g数组赋值,做完这一类后f[i][j]=g[0][i][j]+g[1][i][j]-f[i][j](这里减掉的是两个都没选的情况),这里的循环要倒着来做,有点像分组背包,保证的是同一类数不可能同时出现在两边。

    这道题目中处理质因数的方法很巧妙。虽然做题的时候想到了最多只有一个大于根n的质因数,但是没有灵活的用上。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxnode 1<<8
    #define LL long long
    using namespace std;
    struct use{
        int fi,se;
    }num[505]={0};
    int n;
    LL f[maxnode][maxnode]={0},g[2][maxnode][maxnode]={0},prime[9]={0,2,3,5,7,11,13,17,19};
    int cmp(const use &x,const use &y){return x.fi<y.fi;}
    int next(int i)
    {
        if (num[i].fi==1) return i;
        while(num[i].fi==num[i+1].fi&&i<n) ++i;
        return i;
    }
    int main()
    {
        freopen("dinner.in","r",stdin);
        freopen("dinner.out","w",stdout);
        
        int i,j,k,t,tt;LL p,ans=0;
        scanf("%d%lld",&n,&p);
        for (i=2;i<=n;++i)
        {
            k=i;
            for (j=1;j<=8;++j)
            {
                if (k%prime[j]==0)
                {
                    num[i].se|=1<<(j-1);
                    while(k%prime[j]==0) k/=prime[j];
                }
            }
            num[i].fi=k;
        }
        sort(num+2,num+n+1,cmp);
        f[0][0]=1;
        for (i=2;i<=n;i=tt+1)
        {
            for (j=0;j<=255;++j)
              for (k=0;k<=255;++k)
                  g[0][j][k]=g[1][j][k]=f[j][k];
            tt=next(i);
            for (t=i;t<=tt;++t)
              for (j=255;j>=0;--j)
                for (k=255;k>=0;--k)
                {
                    if ((j&num[t].se)==0) g[1][j][k|num[t].se]=(g[1][j][k|num[t].se]+g[1][j][k])%p;
                    if ((k&num[t].se)==0) g[0][j|num[t].se][k]=(g[0][j|num[t].se][k]+g[0][j][k])%p;
                }
            for (j=0;j<=255;++j)
              for (k=0;k<=255;++k) 
                f[j][k]=((g[0][j][k]+g[1][j][k]-f[j][k])%p+p)%p;
        }
        for (i=0;i<=255;++i)
          for (j=0;j<=255;++j) 
            ans=(ans+f[i][j])%p;
        printf("%lld
    ",ans);
        
        fclose(stdin);
        fclose(stdout);
    }
    View Code

    DAY2

    T1荷马史诗

    题目大意:给n个字符安排一个k进制的替代码,要求一个都不是其他的前缀,同时要求最长的替代码最小。

    思路:可以转化成k叉哈夫曼树,要求树高尽量小。那么像合并果子那样,用一个优先队列维护,在权值相同的时候,先合并高度小的,最后输出就行了。虽然之前没见过,但在测试时根据样例和贪心,还是可以写出来的。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #define LL long long
    using namespace std;
    struct use{
        LL val,dep;
        bool operator <(const use &x)const
        {
            return val==x.val ? dep>x.dep : val>x.val;
        }
    };
    priority_queue<use> que;
    int main()
    {
        freopen("epic.in","r",stdin);
        freopen("epic.out","w",stdout);
        
        int n,k,i,j; LL x,ans=0,sum,ll;
        use y;
        scanf("%d%d",&n,&k);
        for (i=1;i<=n;++i)
        {
            scanf("%I64d",&x);
            que.push((use){x,0});
        }
        j=n;
        if ((n-1)%(k-1)>0) j+=k-1-(n-1)%(k-1);
        for (i=n+1;i<=j;++i) que.push((use){0,0});
        while(j>1)
        {
            sum=ll=0;
            for (i=1;i<=k;++i)
            {
                y=que.top();que.pop();
                ans+=y.val;sum+=y.val;
                ll=max(ll,y.dep);
            }
            j-=k-1;que.push((use){sum,ll+1});
        }
        y=que.top();
        printf("%I64d
    %I64d
    ",ans,y.dep);
        
        fclose(stdin);
        fclose(stdout);
    }
    View Code

    T2品酒大会

    题目大意:给定一个字符串,求lcp(i,j)>=l(l=0~n-1)的对数和val[i]*val[j]的最大值。

    思路:后缀数组的题目。跟差异很像,处理出sa,rank,height数组后分治处理一下就可以了。

    测试时其他有同学按height从大到小排序,然后用并查集做,很神的做法啊。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<ctime>
    #define maxnode 300005
    #define inf 0x7fffffffffffffffLL
    #define LL long long
    using namespace std;
    struct use{
        int minn,minp;
    }tree[maxnode*4]={0};
    struct uu{
        LL maxn,minn;
    }sta;
    int sa[maxnode]={0},rank[maxnode]={0},c[maxnode]={0},t1[maxnode]={0},t2[maxnode]={0},
        height[maxnode]={0},n,m;
    char ss[maxnode];
    LL ans[2][maxnode]={0},val[maxnode]={0};
    bool cmp(int *y,int a,int b,int k)
    {
        int a2,b2;
        a2= a+k>=n ? -1 : y[a+k];
        b2= b+k>=n ? -1 : y[b+k];
        a=y[a];b=y[b];
        return a==b&&a2==b2;
    }
    void build()
    {
        int i,k,p,*x=t1,*y=t2;
        for (i=0;i<m;++i) c[i]=0;
        for (i=0;i<n;++i) ++c[x[i]=(ss[i]-'a')];
        for (i=1;i<m;++i) c[i]+=c[i-1];
        for (i=n-1;i>=0;--i) sa[--c[x[i]]]=i;
        for (k=1;k<=n;k<<=1)
        {
            p=0;
            for (i=n-k;i<n;++i) y[p++]=i;
            for (i=0;i<n;++i) if (sa[i]>=k) y[p++]=sa[i]-k;
            for (i=0;i<m;++i) c[i]=0;
            for (i=0;i<n;++i) ++c[x[y[i]]];
            for (i=1;i<m;++i) c[i]+=c[i-1];
            for (i=n-1;i>=0;--i) sa[--c[x[y[i]]]]=y[i];
            swap(x,y);m=1;x[sa[0]]=0;
            for (i=1;i<n;++i) x[sa[i]]=cmp(y,sa[i],sa[i-1],k) ? m-1 : m++;
            if (m>=n) break;
        }
    }
    void pre()
    {
        int i,j,k=0;
        for (i=0;i<n;++i) rank[sa[i]]=i;
        for (i=0;i<n;++i)
        {
            if (!rank[i]) continue;
            if (k) --k; j=sa[rank[i]-1];
            while(ss[i+k]==ss[j+k]) ++k;
            height[rank[i]]=k;
        }
    }
    use updata(use x1,use x2)
    {
        if (x1.minn<=x2.minn) return x1;
        else return x2;
    }
    uu updata2(uu x1,uu x2)
    {
        uu x3;
        x3.minn=min(x1.minn,x2.minn);
        x3.maxn=max(x1.maxn,x2.maxn);
        return x3;
    }
    void buildt(int i,int l,int r)
    {
        int mid;
        if (l==r)
        {
            tree[i].minn=height[l];tree[i].minp=l;return;
        }
        mid=(l+r)/2;
        buildt(i*2,l,mid);buildt(i*2+1,mid+1,r);
        tree[i]=updata(tree[i*2],tree[i*2+1]);
    }
    use task(int i,int l,int r,int ll,int rr)
    {
        int mid; use x1,x2;
        if (ll<=l&&r<=rr) return tree[i];
        x1.minn=x2.minn=x1.minp=x2.minp=2100000000LL;
        mid=(l+r)/2;
        if (ll<=mid) x1=task(i*2,l,mid,ll,rr);
        if (rr>mid) x2=task(i*2+1,mid+1,r,ll,rr);
        return updata(x1,x2);
    }
    uu work(int l,int r)
    {
        if (l>=r) 
        {
           if (l==r) return (uu){val[sa[l]],val[sa[l]]};
           else return sta;
        }
        use x; x=task(1,0,n-1,l+1,r);
        ans[0][x.minn]+=(LL)(x.minp-l)*(LL)(r-x.minp+1);
        uu x1,x2;
        x1=work(l,x.minp-1);x2=work(x.minp,r);
        ans[1][x.minn]=max(ans[1][x.minn],max(x1.maxn*x2.maxn,max(x1.minn*x2.minn,
                       max(x1.maxn*x2.minn,x1.minn*x2.maxn))));
        return updata2(x1,x2);
    }
    int main()
    {
        freopen("savour.in","r",stdin);
        freopen("savour.out","w",stdout);
        
        int i,j;
        scanf("%d",&n);m=26;
        while(1)
        {
            ss[0]=getchar();
            if (ss[0]>='a'&&ss[0]<='z') break;
        }
        for (i=1;i<n;++i) ss[i]=getchar();
        for (i=0;i<n;++i) scanf("%I64d",&val[i]);
        build();pre();buildt(1,0,n-1);
        memset(ans[1],128,sizeof(ans[1]));
        sta.maxn=ans[1][maxnode-1];sta.minn=inf;work(0,n-1);
        for (i=n-1;i>=0;--i)
        {
            ans[0][i]+=ans[0][i+1];
            ans[1][i]=max(ans[1][i],ans[1][i+1]);
        }
        for (i=0;i<n;++i)
          printf("%I64d %I64d
    ",ans[0][i],(ans[0][i]==0 ? 0 : ans[1][i]));
          
        fclose(stdin);
        fclose(stdout);
    }
    View Code
  • 相关阅读:
    mysqldump 导出数据库为DBname的表名为Tname的表结构 导出数据库的所有表的表结构
    mysqldump 备份某张表 Warning: A partial dump from a server that has GTIDs will by default include the GTIDs of all transactions,
    nfs missing codepage or helper program, or other error
    date 增加一个小时 减少一个小时
    mysqldump 备份单个数据库
    mysql删除账户
    怎么删除某个用户的所有帖子?
    mongodb删除重复数据
    ReSharper2018破解详细方法
    激活windows和office
  • 原文地址:https://www.cnblogs.com/Rivendell/p/4730579.html
Copyright © 2011-2022 走看看