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; }
过了签到题后,接着就悲剧了。。。。。。。。。。。。。。
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)); } }
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; }
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); } } }
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; }
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; }
用数组模拟一下就好了,昨天一直调到现在,终于发现是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机房那么冷的空调,又没吃早餐,头脑本来一片混乱,怎么可能写出模拟题。。。
下一场的目标当然是抢名额,会有把我们和对面那些队拉开差距的比赛,但是这场如果我们发挥稳定不卡题的话,拉开差距? 并不能!