2017-10-09离线赛

来源:互联网 发布:yy淘宝兼职可信吗 编辑:程序博客网 时间:2024/06/07 06:04

据说是镇海中学出的题目

大体状况

255/300

T1 xor

题目大意

有一个数列,取一个区间,使区间最大值与次大值异或值最大。

分析

P40

暴力O(n2)
维护最大值与次大值。

P100

这种题目肯定只有两种方法。
枚举最大值,查找次大值。
枚举次大值,查找最大值。
然后显然是后一种好写。
考虑其匹配的是哪个最大值。
用单调栈处理出前一个大于等于其的值。
设其位置为l,当前位置为r。
如果[l,r]范围扩大,这个答案不变或此数不能成为次大值。
如果[l,r]范围缩小,此数会变成最大值。
前后各扫一遍即可。

代码

然后数组少打一个0减少20分。
感觉是十分低级的错误啊。

#include<bits/stdc++.h>using namespace std;#define Komachi is retarded#define REP(i,a,b) for(int i=(a),i##_end_=(b);i<i##_end_;i++)#define DREP(i,a,b) for(int i=(a),i##_end_=(b);i>i##_end_;i--)#define LL long long#define chkmin(a,b) a=min(a,b)#define chkmax(a,b) a=max(a,b)#define M 2000004void Rd(int &res){    char c;res=0;    while((c=getchar())<48);    do res=(res<<3)+(res<<1)+(c^48);    while((c=getchar())>47);}int n,A[M];struct P40{    void Solve(){        int Ans=0;        REP(i,0,n-1){            int x=max(A[i],A[i+1]),y=min(A[i],A[i+1]);            chkmax(Ans,x^y);            REP(j,i+2,n){                if(A[j]>=x)y=x,x=A[j];                else if(A[j]>y)y=A[j];                chkmax(Ans,x^y);            }        }        printf("%d\n",Ans);    }}P40;struct P100{    int Stk[M],Top;    void Solve(){        int Ans=0;        REP(i,0,n){            while(Top && Stk[Top]<A[i])Top--;            if(Top)chkmax(Ans,Stk[Top]^A[i]);            Stk[++Top]=A[i];        }        Top=0;        DREP(i,n-1,-1){            while(Top && Stk[Top]<A[i])Top--;            if(Top)chkmax(Ans,Stk[Top]^A[i]);            Stk[++Top]=A[i];        }        printf("%d\n",Ans);    }}P100;int main(){    freopen("xor.in","r",stdin);    freopen("xor.out","w",stdout);    Rd(n);    REP(i,0,n)Rd(A[i]);    if(n<=5000)P40.Solve();     else P100.Solve();    return 0;}

T2 atom

题目描述

求一棵看起来非常奇怪的树的子树节点个数。
然而边要自己造,点数达到109

分析

P75

那么你就暴力建边暴力DP求一下就好了。
代码实现起来稍微麻烦一些。

P100

因为这个题目的各种性质,
所以剪掉叶节点后点数一下子就变成了5105以内。
然后叶节点可以排列组合算,
直接DFS或者一次DP处理均可。

代码

这里选择了对每种n建树并计算出所有答案。
然而没有DFS跑得快。

#include<bits/stdc++.h>using namespace std;#define Komachi is retarded#define REP(i,a,b) for(int i=(a),i##_end_=(b);i<i##_end_;i++)#define DREP(i,a,b) for(int i=(a),i##_end_=(b);i>i##_end_;i--)#define LL long long#define chkmin(a,b) a=min(a,b)#define chkmax(a,b) a=max(a,b)int T,n,Case;char C[14];int Base[]={0,1,10,100,1000,10000,100000,1000000,10000000,100000000,404};int Fac[]={1,1,2,6,24,120,720,5040,40320,362880,3628800};struct P100{    static const int M=50004;    map<int,int>ID[14];    bool Do[14];    int Re[M],Sz[14][M];    int Next[M],To[M],Head[M],Tim[M],id,tot,tar;    void Add_Edge(int u,int v){        if(Tim[u]!=tar)Tim[u]=tar,Head[u]=0;        Next[++tot]=Head[u],To[Head[u]=tot]=v;    }    #define LREP(i,A) for(int i=Head[A];i;i=Next[i])    void Clear(){        tot=id=0;        tar++;    }    void DFS(int A){        Sz[n][A]=1;        if(Tim[A]==tar)LREP(i,A)            DFS(To[i]),Sz[n][A]+=Sz[n][To[i]];        if(Sz[n][A]==1){            int p=Re[A],k=Fac[n],zero=n;            if(p==1)return;            REP(i,0,n){                k/=Fac[p%10];                zero-=p%10;                p/=10;            }            k/=Fac[zero];            Sz[n][A]+=k;        }    }    int A[14];    void Build(int pos,int x,int S,bool k){        if(pos>n){            if(!S)return;            if(k){                int y=0;                REP(i,1,n+1)                    y+=Base[A[i]];                if(y!=x)Add_Edge(ID[n][y],ID[n][x]);            }            else ID[n][x]=++id,Re[id]=x;            return;        }        REP(i,0,(n-S)+1)            A[pos]=i,Build(pos+1,x+Base[pos]*i,S+i,k);    }    void Init(){        if(Do[n])return;        Clear();        Build(1,0,0,0);        Build(1,0,0,1);        DFS(ID[n][1]);        Sz[n][ID[n][0]=0]=0;        Do[n]=1;    }    void Solve(){        Init();        int x=0,j=0;        REP(i,0,n){            if(C[i]-'0'>n){printf("Case #%d: %d\n",++Case,0);return;}             j+=C[i]-'0';            x+=Base[i+1]*(C[i]-'0');        }        printf("Case #%d: %d\n",++Case,j>n?1:Sz[n][ID[n][x]]);    }}P100;int main(){    scanf("%d",&T);    while(T--){        scanf("%s",C);        n=strlen(C);        P100.Solve();    }    return 0;}

T3 chocolate

分析

假的T3。

P30

有一个p2
然后就可以简单贪心。
p==1时,答案肯定是n
p==2时,肯定先喂%p=0再喂%p=1,然后这个随便算。

P60

然后是p3
感觉还是能贪心。
先喂%p=0,然后%p=1或%p=2都是需要三个相同才能得到一个收益。
然后它们配对的话两个就可以得到一个收益。
所以算一下就好了。

P100

然后是p4
先想了想枚举一个东西再贪心。
然后发现没有必要。
其实按着上面的思路接着分类讨论一下贪心即可。
具体细节看代码吧。

代码

#include<bits/stdc++.h>using namespace std;#define Komachi is retarded#define REP(i,a,b) for(int i=(a),i##_end_=(b);i<i##_end_;i++)#define DREP(i,a,b) for(int i=(a),i##_end_=(b);i>i##_end_;i--)#define LL long long#define chkmin(a,b) a=min(a,b)#define chkmax(a,b) a=max(a,b)void Rd(int &res){    char c;res=0;    while((c=getchar())<48);    do res=(res<<3)+(res<<1)+(c^48);    while((c=getchar())>47);}#define M 10004 int T,n,p,A[M],Case;struct P30{    int Cnt[4];    void Solve(){        memset(Cnt,0,sizeof(Cnt));        REP(i,0,n)Cnt[A[i]&1]++;        int Ans=Cnt[0]+(Cnt[1]>>1)+(Cnt[1]&1);        printf("Case #%d: %d\n",++Case,Ans);    }}P30;struct P60{    int Cnt[4];    void Solve(){        memset(Cnt,0,sizeof(Cnt));        REP(i,0,n)Cnt[A[i]%3]++;        int Ans=min(Cnt[1],Cnt[2]);        Cnt[1]-=Ans;        Cnt[2]-=Ans;        Ans+=(Cnt[1]+3-1)/3;        Ans+=(Cnt[2]+3-1)/3;        Ans+=Cnt[0];        printf("Case #%d: %d\n",++Case,Ans);    }}P60;struct P100{    int Cnt[4];    void Solve(){        memset(Cnt,0,sizeof(Cnt));        REP(i,0,n)Cnt[A[i]%4]++;        int Ans=min(Cnt[1],Cnt[3]);        Cnt[1]-=Ans;        Cnt[3]-=Ans;        int p=Cnt[1]==0?3:1;         Ans+=(Cnt[2]>>1);        Cnt[2]=Cnt[2]&1;        if(Cnt[2]){            if(Cnt[p]>=2){                Ans++,Cnt[p]-=2;                Ans+=(Cnt[p]+4-1)/4;            }            else Ans++;        }        else Ans+=(Cnt[p]+4-1)/4;        Ans+=Cnt[0];        printf("Case #%d: %d\n",++Case,Ans);    }}P100;int main(){    freopen("chocolate.in","r",stdin);    freopen("chocolate.out","w",stdout);    Rd(T);    while(T--){        Rd(n),Rd(p);        REP(i,0,n)Rd(A[i]);        if(p==1)printf("Case #%d: %d\n",++Case,n);        else if(p==2)P30.Solve();        else if(p==3)P60.Solve();        else P100.Solve();    }    return 0;}

总结

十分正常的题目与分数。
时间分配略少了一些,否则应该能写出T2。
T2的P75实现花的时间较多,然而暴力DFS不优化也可以过。
T3是假T3,T1失误。

原创粉丝点击