• 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
  • 相关阅读:
    mybatis基础学习3---特殊sql语句(备忘)
    5.dos网络配置命令,重新获取ip刷新dns
    Guarded Suspension设计模式
    多线程Future设计模式
    多线程不可变对象设计模式immutable
    多线程读写锁分离设计模式
    多个人过门引出线程安全问题
    库存管理系统项目总结
    简单认识C#
    数据类型,变量,与运算符
  • 原文地址:https://www.cnblogs.com/Rivendell/p/4730579.html
Copyright © 2020-2023  润新知