2015长春网络赛总结

2015长春网络赛总结

1007:签到题,区间最值查询,暴力或线段树或者ST都行。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define RI(a) scanf("%d",&(a))
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

using namespace std;

const int maxn=1000100;
const int INF=(1<<29);

int n,a[maxn];
int l,r;
int q;
int Max[maxn<<2];

void push_up(int rt)
{
    Max[rt]=max(Max[rt<<1],Max[rt<<1|1]);
}

void build(int l,int r,int rt)
{
    if(l==r){
        RI(Max[rt]);
        //cout<<l<<" "<<r<<" "<<rt<<" "<<Max[rt]<<endl;
        return;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    push_up(rt);
}

int query(int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R) return Max[rt];
    int m=(l+r)>>1;
    int res=-INF;
    if(L<=m) res=max(res,query(L,R,lson));
    if(R>m) res=max(res,query(L,R,rson));
    return res;
}

int main()
{
    //freopen("in.txt","r",stdin);
    int T;cin>>T;
    while(T--){
        RI(n);
        //cout<<"_"<<n<<endl;
        build(1,n,1);
        RI(q);
        //cout<<"__"<<q<<endl;
        while(q--){
            RI(l);RI(r);
            //cout<<l<<" "<<r<<" ";
            printf("%d\n",query(l,r,1,n,1));
        }
    }
    return 0;
}
View Code

过了签到题后,接着就悲剧了。。。。。。。。。。。。。。

 

1010:lucas+中国剩余定理。。。

求大组合数对几个不同的素数乘积取模。

比赛的时候翻了一下紫书,看到了中国剩余定理,对着题目脑补了一下,出了思路。然而。。。于是打开博客找lucas模板,有从网上复制了中国剩余定理的模板,交上去TLE了。。然后把lucas模板换成了预处理阶乘版本的,再交WA了。。然后一直调。。。一直换模板。。。赛后发现是lucas模板不预处理阶乘版本的会TLE,之后的完全不是模板的问题,自己将预处理阶乘时的p取成了100007,以为是素数。。。100007居然不是素数!!!。。。。。另一个注意点就是剩余定理的模板上有个三个10^18相乘对10^18的情况,会爆longlong,需要模拟乘法,这点比赛的时候倒是注意到了。。。。赛后把p从100007换成素数就过了。。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define RI(a) scanf("%d",&(a))
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=(1<<29);

ll n,m,k;
ll p[maxn],b[maxn];
ll F[maxn];

void Init(ll p)
{
    F[0]=1;
    REP(i,1,p) F[i]=(F[i-1]*i)%p;
}

ll mul(ll a,ll b,ll p)
{
    ll res=0;
    while(b){
        if(b&1) res=(res+a)%p;
        a=(a+a)%p;
        b>>=1;
    }
    return res;
}

ll inv(ll a,ll m)
{
    if(a==1) return 1;
    return inv(m%a,m)*(m-m/a)%m;
}

ll lucas(ll n,ll m,ll p)
{
    ll ans=1;
    while(n&&m){
        ll a=n%p;
        ll b=m%p;
        if(a<b) return 0;
        ans=ans*F[a]%p*inv(F[b]*F[a-b]%p,p)%p;
        n/=p;m/=p;
    }
    return ans;
}

void gcd(ll a,ll b,ll &d,ll &x,ll &y)
{
    if(!b){
        b=a;x=1;y=0;
    }
    else{
        gcd(b,a%b,d,y,x);
        y-=x*(a/b);
    }
}

ll china(ll n,ll *a,ll *m)
{
    ll M=1,d,y,x=0;
    REP(i,0,n-1) M*=m[i];
    REP(i,0,n-1){
        ll w=M/m[i];
        gcd(m[i],w,d,d,y);
        x=(x+mul(y,mul(w,a[i],M),M))%M;
    }
    return (x+M)%M;
}

int main()
{
    freopen("in.txt","r",stdin);
    int T;cin>>T;
    while(T--){
        scanf("%I64d%I64d%I64d",&n,&m,&k);
        REP(i,0,k-1){
            scanf("%d",&p[i]);
            Init(p[i]);
            b[i]=lucas(n,m,p[i]);
        }
        printf("%I64d\n",china(k,b,p));
    }
}
View Code

1005:离线并查集。

对所有的询问离线和边排序一下就好了。

这题比赛的时候是队友写的,居然意外地没过!!!!!!!!都怪自己傻逼一直调1010,浪费了大部分时间,要是先把1010暂放,去帮队友调这题肯定就过了。。。。后来本来也有时间,被队友叫去写1001题的傻逼模拟了,而且在思路没理清的时候就写了,也没注意坑点。。。。悲剧。。。。。。。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define RI(a) scanf("%d",&(a))
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=(1<<29);

int N,M,Q;
struct Edge
{
    int u,v,w;/// id isEdge ask
    int ans;
    friend bool operator<(Edge A,Edge B)
    {
        if(A.w<B.w) return 1;
        if(A.w==B.w) return A.v>B.v;
        return 0;
    }
};
Edge e[maxn];
Edge q[maxn];
Edge eq[maxn];
int cnt;
int fa[maxn];
int sum[maxn];

bool cmpID(Edge A,Edge B)
{
    return A.u<B.u;
}

int Find(int x)
{
    return fa[x]==x?x:fa[x]=Find(fa[x]);
}

int main()
{
    freopen("in.txt","r",stdin);
    int T;cin>>T;
    while(T--){
        scanf("%d%d%d",&N,&M,&Q);
        REP(i,1,M) scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
        REP(i,1,Q) scanf("%d",&q[i].w),q[i].u=i,q[i].v=-1;
        cnt=0;
        REP(i,1,M) eq[++cnt]=e[i];
        REP(i,1,Q) eq[++cnt]=q[i];
        sort(eq+1,eq+cnt+1);
        REP(i,0,maxn-1) fa[i]=i;
        REP(i,1,N) sum[i]=1;
        int Ans=0;
        REP(i,1,cnt){
            if(eq[i].v!=-1){
                int u=eq[i].u,v=eq[i].v,w=eq[i].w;
                int x=Find(u),y=Find(v);
                if(x!=y){
                    Ans-=sum[y]*(sum[y]-1)+sum[x]*(sum[x]-1);
                    sum[x]+=sum[y];
                    sum[y]=0;
                    fa[y]=x;
                    Ans+=sum[x]*(sum[x]-1);
                }
            }
            else eq[i].ans=Ans;
        }
        Q=0;
        REP(i,1,cnt){
            if(eq[i].v==-1) q[++Q]=eq[i];
        }
        sort(q+1,q+Q+1,cmpID);
        REP(i,1,Q) printf("%d\n",q[i].ans);
    }
    return 0;
}
View Code

1001:优先队列模拟。

直接优先队列模拟一下就行了,注意最后没进去的都要按权值进去,当时问了一下队友是不是按标号进去的,队友说是,郁闷。。。还有询问是不按顺序的。。。。模拟题最重要的就是防坑。比赛的时候真是一片混乱,写完就交,根本没意识关注这些坑点,一直卡到比赛结束。。。。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<algorithm>
#define RI(a) scanf("%d",&(a))
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

using namespace std;

const int maxn=150100;
const int INF=(1<<29);

struct Node
{
    char s[210];
    int val,t;
    friend bool operator<(Node A,Node B)
    {
        if(A.val<B.val) return 1;
        if(A.val==B.val) return A.t>B.t;
        return 0;
    }
};
int N,M,Q;
int x;
Node a[maxn];
struct Ask
{
    int t,c;
    friend bool operator<(Ask A,Ask B)
    {
        return A.t<B.t;
    }
};
Ask ask[maxn];

int main()
{
    freopen("in.txt","r",stdin);
    int T;cin>>T;
    while(T--){
        scanf("%d%d%d",&N,&M,&Q);
        REP(i,1,N){
            scanf("%s%d",a[i].s,&a[i].val);
            a[i].t=i;
        }
        REP(i,1,M){
            scanf("%d%d",&ask[i].t,&ask[i].c);
        }
        sort(ask+1,ask+M+1);
        priority_queue<Node> q;
        vector<Node> ans;
        int tot=1;
        REP(i,1,M){
            while(tot<=N&&a[tot].t<=ask[i].t){
                q.push(a[tot++]);
            }
            int c=0;
            while(!q.empty()){
                if(c==ask[i].c) break;
                ans.push_back(q.top());
                q.pop();
                c++;
            }
        }
        while(tot<=N) q.push(a[tot++]);
        while(!q.empty()){
            ans.push_back(q.top());
            q.pop();
        }
        //cout<<ans.size()<<endl;
        while(Q--){
            scanf("%d",&x);
            if(Q) printf("%s ",ans[x-1].s);
            else printf("%s\n",ans[x-1].s);
        }
    }
}
View Code

1006:后缀数组。。。

按一般循环串的处理方法,直接把前len-1个接在原串后面,然后求个后缀数组,扫一下找字典序最大的符合条件的最靠前的sa[]就行了。就是傻逼模板题啊。。。代码实现上比1001,1010要简单多了。。。。比赛的时候场面真是太混乱了,顾不上看这题了。。。

要是早看这题,结果就会不一样了。。。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<queue>
#include<set>
#define RI(a) scanf("%d",&(a))
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=(1<<29);

int len;
char s[maxn],fs[maxn];
int str[maxn];
int n;
int pos1,pos2;
char ans1[maxn],ans2[maxn];

int sa[maxn];
int t1[maxn],t2[maxn],c[maxn];
int Rank[maxn],height[maxn];

void build_sa(int s[],int n,int m)
{
    int i,j,p,*x=t1,*y=t2;
    for(i=0;i<m;i++)c[i]=0;
    for(i=0;i<n;i++)c[x[i]=s[i]]++;
    for(i=1;i<m;i++)c[i]+=c[i-1];
    for(i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
    for(j=1;j<=n;j<<=1)
    {
        p=0;
        for(i=n-j;i<n;i++)y[p++]=i;
        for(i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;
        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);
        p=1;x[sa[0]]=0;
        for(i=1;i<n;i++)
            x[sa[i]]=y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+j]==y[sa[i]+j]?p-1:p++;
        if(p>=n)break;
        m=p;
    }
}
void getHeight(int s[],int n)
{
    int i,j,k=0;
    for(i=0;i<=n;i++) Rank[sa[i]]=i;
    for(i=0;i<n;i++)
    {
        if(k)k--;
        j=sa[Rank[i]-1];
        while(s[i+k]==s[j+k])k++;
        height[Rank[i]]=k;
    }
}

void getMax1()
{
    int p=0;
    for(int i=n;i>=1;i--){
        if(sa[i]<len){
            p=i;break;
        }
        else continue;
    }
    pos1=sa[p];
    for(int i=p;i>=2;i--){
        if(height[i]>=len){
            pos1=min(pos1,sa[i-1]);
        }
        else break;
    }
    strncpy(ans1,s+pos1,len);
}

void getMax2()
{
    int p=0;
    for(int i=n;i>=1;i--){
        if(sa[i]<len){
            p=i;break;
        }
        else continue;
    }
    //REP(i,0,n) cout<<sa[i]<<" ";cout<<endl;
    pos2=sa[p];
    for(int i=p;i>=2;i--){
        if(height[i]>=len){
            pos2=max(pos2,sa[i-1]);
        }
        else break;
    }
    strncpy(ans2,fs+pos2,len);
    pos2=len-1-pos2;
}

int main()
{
    freopen("in.txt","r",stdin);
    int T;cin>>T;
    while(T--){
        scanf("%d%s",&len,s);
        REP(i,0,len-1) fs[i]=s[len-1-i];
        fs[len]=0;
        strncat(s,s,len-1);
        strncat(fs,fs,len-1);
        n=strlen(s);
        //cout<<s<<" "<<fs<<" "<<n<<endl;
        REP(i,0,n) str[i]=s[i];
        build_sa(str,n+1,300);
        getHeight(str,n);
        getMax1();
        REP(i,0,n) str[i]=fs[i];
        build_sa(str,n+1,300);
        getHeight(str,n);
        getMax2();
        //cout<<ans1<<" "<<ans2<<endl;
        if(strcmp(ans1,ans2)>0) printf("%d %d\n",pos1+1,0);
        else if(strcmp(ans1,ans2)<0) printf("%d %d\n",pos2+1,1);
        else{
            //cout<<pos1<<" "<<pos2<<endl;
            if(pos1<=pos2) printf("%d %d\n",pos1+1,0);
            else printf("%d %d\n",pos2+1,1);
        }
    }
    return 0;
}
View Code

1007:直接模拟建树。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define RI(a) scanf("%d",&(a))
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=(1<<29);

int n,a;
struct Node
{
    int id;
    int l,r;
};
Node node[maxn];
int p;
int q,k;

int go(int a,int now)
{
    if(a<node[now].id){
        if(node[now].l==0) return now;
        return go(a,node[now].l);
    }
    else{
        if(node[now].r==0) return now;
        return go(a,node[now].r);
    }
}

void dfs(int k,int now)
{
    if(node[now].id==k) return;
    if(k<node[now].id){
        printf("E");
        dfs(k,node[now].l);
    }
    else{
        printf("W");
        dfs(k,node[now].r);
    }
}

int main()
{
    freopen("in.txt","r",stdin);
    int T;cin>>T;
    while(T--){
        cin>>n;
        p=0;
        MS0(node);
        RI(a);
        node[++p]={a,0,0};
        int now=p;
        REP(i,2,n){
            RI(a);
            now=go(a,1);
            node[++p]={a,0,0};
            if(a<node[now].id) node[now].l=p;
            else node[now].r=p;
        }
        RI(q);
        while(q--){
            RI(k);
            dfs(k,1);
            printf("\n");
        }
    }
    return 0;
}
View Code

 

用数组模拟一下就好了,昨天一直调到现在,终于发现是go(a,1)写成go(a,now)了。。。

这种错误很难发现,两种方法,一种是把代码写得尽量简洁清晰,然后一步步逐个检查每个部分,另一种就是重写。比赛的时候应该先调试找数据,没发现什么就不要交,应该逐步检查,如果没检查出来也不要交,应该重写一遍,然后确定没问题后交一下,如果再不过就暂时去看其它题。

这场太悲剧了,上面几道题只过了签到,再加上队友的1002求联通分量的,本来该过7题的比赛居然只过了2题。。。。要是当时暂时放弃1010,去帮队友写1005就好了。。。比赛的时候自己前3个多小时一直在调1010换模板,后一个小时多1001卡到比赛结束。。。

总的来说,下一场可不能这么混乱地卡题了。。。模板要提前准备好,然后要相信模板没问题,如果WA了一定是自己代码的问题。如果卡题了要先把那道题先放放,先去帮队友调题目或者帮队友写其它题,让队友看新题(这个因为我英语能力不怎么样),不能像这场这样一道题卡3个多小时。模拟题要写之前一定要想好思路,和队友先交流一下,再写,最好能够先想好坑点。

 

该学的知识点都学到了,该过的题却没过,这是比赛中最忌讳的。如果说当时省赛是因为什么都不会打铁,不会离线并查集,不会线段树,不会数位dp,不会kmp,不会连通图,不会lca,不知道BSGS,但是,现在完全不一样了,我们学了并查集,离线,线段树,树状数组,数位dp,kmp,lca,后缀数组,中国剩余定理,树链剖分,连通图,网络流和二分图,状压dp,单调栈,同时又做了一些dp题。。。很多题我们都可以做的却没有在比赛中发挥出来,这不是知识点的问题,而是比赛经验的问题。比如今天这场,lucas和剩余定理学了,思路也出了,离线并查集也是,优先队列也是,模拟建树和后缀数组是没看,但并不是我们没时间看,而是比赛策略问题,卡题了。这些题知识点都学过,思路也出了,如果连这些都不能过的话还打什么区域赛。

 

希望我们能在周末的网络赛之前能再训练两场保持状态,还有一定要帮队友把这场的题全补了。

还有就是比赛的前一天一定不要熬夜,当时前一天自己半夜4点才睡。。。第二天碰上207机房那么冷的空调,又没吃早餐,头脑本来一片混乱,怎么可能写出模拟题。。。

下一场的目标当然是抢名额,会有把我们和对面那些队拉开差距的比赛,但是这场如果我们发挥稳定不卡题的话,拉开差距? 并不能!

 

posted @ 2015-09-14 20:14  __560  阅读(331)  评论(0编辑  收藏  举报