2017-10-17离线赛
来源:互联网 发布:java nanotime 转毫秒 编辑:程序博客网 时间:2024/06/06 16:48
大体状况
300/300
?因为是真题所以稍微简单一些吗= =
题目来源 NOIP2011 Day2
T1 factor
分析
求
二项式杨辉三角展开后
所以可以直接快速幂求得。
时间复杂度
然而
代码
#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 chkmax(a,b) a=max(a,b)#define chkmin(a,b) a=min(a,b)#define LL long longvoid 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 1004#define Mod 10007int Fac[M];int a,b,k,n,m;int Pow(int x,int p){ int Res=1; for(int k=x%Mod;p;p>>=1,k=k*k%Mod)if(p&1)(Res*=k)%=Mod; return Res;}int main(){ Rd(a),Rd(b),Rd(k),Rd(n),Rd(m); Fac[0]=1; REP(i,1,k+1)Fac[i]=Fac[i-1]*i%Mod; if(k==0)puts("1"); else printf("%d\n",Fac[k]*Pow(Fac[n],Mod-2)%Mod*Pow(Fac[m],Mod-2)%Mod*Pow(a,n)%Mod*Pow(b,m)%Mod); return 0;}
T2 qc
分析
二分
然后就要考虑如何在区间内查询
首先想到的当然是主席树(不
然后主席树维护的话是
发现一次查询是连续的m次,然后n与m是同阶的。
所以明明扫一遍对
代码
#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 chkmax(a,b) a=max(a,b)#define chkmin(a,b) a=min(a,b)#define LL long longvoid 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 200004int n,m,W[M],V[M],L[M],R[M];LL S;struct P100{ int P[M],sz; int Cnt[M]; LL Sum[M]; LL Y(int x){ REP(i,1,n+1) Cnt[i]=Cnt[i-1]+(W[i]>=x), Sum[i]=Sum[i-1]+((W[i]>=x)*V[i]); LL Res=0; REP(i,0,m){ Res+= (Sum[R[i]]-Sum[L[i]-1])* (Cnt[R[i]]-Cnt[L[i]-1]); } return Res; } void Solve(){ REP(i,1,n+1)P[i]=W[i]; sort(P+1,P+n+1); sz=unique(P+1,P+n+1)-P-1; REP(i,1,n+1)W[i]=lower_bound(P+1,P+sz+1,W[i])-P; int l=1,r=sz; LL Ans=S; while(l<=r){ int Mid=l+r>>1; LL Tmp=Y(Mid); chkmin(Ans,abs(S-Tmp)); if(Tmp>S)l=Mid+1; else r=Mid-1; } REP(x,max(1,l-2),min(sz+1,l+2))chkmin(Ans,abs(S-Y(x))); printf("%lld\n",Ans); }}P100;int main(){ Rd(n),Rd(m),scanf("%lld",&S); REP(i,1,n+1)Rd(W[i]),Rd(V[i]); REP(i,0,m)Rd(L[i]),Rd(R[i]); P100.Solve(); return 0;}
T3 bus
分析
P60
这题贪心的思路还是比较显然的。
处理出该加速器影响的区间(即均满足
加速器之间不会互相影响。
因此满足最优性,那么直接贪心的复杂度为
即枚举每个位置计算其减少量,然后使用加速器。
P100
上面的思路稍微改改就能得到
处理出区间后,显然在更左用加速器更优。
用一个指针扫过去得到每个位置的值即可。
然后这样就能过所有数据。
代码
#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 chkmax(a,b) a=max(a,b)#define chkmin(a,b) a=min(a,b)#define LL long longvoid Rd(int &res){ char c;res=0; while((c=getchar())<48); do res=(res<<3)+(res<<1)+(c^48); while((c=getchar())>47);}#define N 1004#define M 10004int n,m,k,D[N],Cnt[N],Mx[N],Tim[N];int T[M],A[M],B[M];bool Delete(){ REP(i,1,n) Tim[i+1]=max(Tim[i],Mx[i])+D[i]; int Pos=0,Max=-1; for(int i=1,j;i<n;i++) if(D[i]>0){ j=i+1; int Res=Cnt[j]; while(Tim[j]>Mx[j]) Res+=Cnt[++j]; if(Res>Max) Max=Res,Pos=i; i=j-1; } if(Max==-1)return 1; D[Pos]--; return 0;}int main(){ Rd(n),Rd(m),Rd(k); REP(i,1,n)Rd(D[i]); REP(i,0,m){ int t,a,b; Rd(t),Rd(a),Rd(b); Cnt[b]++; chkmax(Mx[a],t); T[i]=t,A[i]=a,B[i]=b; } REP(i,0,k)if(Delete())break; REP(i,1,n) Tim[i+1]=max(Tim[i],Mx[i])+D[i]; int Ans=0; REP(i,0,m) Ans+=Tim[B[i]]-T[i]; printf("%d\n",Ans); return 0;}
优化
注意到上面的方法进行了很多次重复的计算Time,
以及重复地查找那些可能已知的值,可以对于其采用区间更新的方法。
区间更新仍然要在所有当前可用的区间中寻找最大值。
所以可以用一个堆来存放当前所有区间。
每次提取出乘客数最大的区间,查看其是否合法并用最小的可能值更新。
然后拆成两半。
理论复杂度最差为
代码
#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 chkmax(a,b) a=max(a,b)#define chkmin(a,b) a=min(a,b)#define LL long longvoid Rd(int &res){ char c;res=0; while((c=getchar())<48); do res=(res<<3)+(res<<1)+(c^48); while((c=getchar())>47);}#define N 1004int n,m,k,D[N],Cnt[N],Mx[N],Tim[N],Ans;struct Node{ int l,r,x; bool operator <(const Node &_)const{ return x<_.x; }};priority_queue<Node>Q;int main(){ Rd(n),Rd(m),Rd(k); REP(i,1,n)Rd(D[i]); REP(i,0,m){ int t,a,b; Rd(t),Rd(a),Rd(b); Cnt[b]++; chkmax(Mx[a],t); Ans-=t; } REP(i,1,n) Tim[i+1]=max(Tim[i],Mx[i])+D[i]; REP(i,1,n+1) Ans+=Cnt[i]*Tim[i]; REP(i,2,n+1) Cnt[i]+=Cnt[i-1]; Q.push((Node){1,n,Cnt[n]-Cnt[1]}); while(!Q.empty() && k){ Node T=Q.top();Q.pop(); int l=T.l,r=T.r,x=T.x; int Pos=-1,Use=min(k,D[l]); REP(i,l+1,r)if(Use>Tim[i]-Mx[i]) Use=Tim[i]-Mx[i],Pos=i; if(Use>0){//满足要求,可以更新 D[l]-=Use; k-=Use; Ans-=x*Use; REP(i,l,r)Tim[i+1]=max(Tim[i],Mx[i])+D[i]; } if(~Pos){//拆为两个区间 Q.push((Node){l,Pos,Cnt[Pos]-Cnt[l]}); Q.push((Node){Pos,r,Cnt[r]-Cnt[Pos]}); } else if((++l)<r)Q.push((Node){l,r,Cnt[r]-Cnt[l]}); } printf("%d\n",Ans); return 0;}
另一个方法
这个贪心还可以用最小费用最大流来做。
然而比暴力还慢,
最差复杂度为
首先裂点
从每个
作为可被更新到的分界线。
从源点
表示最大加速的限制。
从每个
表示每个加速器在这个点带来的收益
从每个
作为加速器的结束位置。
然后套模板费用流。
代码
#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 chkmax(a,b) a=max(a,b)#define chkmin(a,b) a=min(a,b)#define LL long long#define INF 0x3f3f3f3fvoid 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 1044struct Edge{ int u,v,w,c;}E[(M<<3)+44];template<const int Len,const int Num>struct Linklist{ int G[Len],Next[Len],Head[Num],tot; int operator [](int x){return G[x];} void pb(int u,int id){Next[++tot]=Head[u],G[Head[u]=tot]=id;} #define LREP(i,a,G) for(int i=G.Head[a];i;i=G.Next[i])};Linklist<(M<<3)+44,(M<<1)>G;int n,m,k,etot;void Add_Edge(int u,int v,int w,int c){ assert(etot<((M<<3)+44)); E[etot]=(Edge){u,v,w,c}; G.pb(u,etot++); E[etot]=(Edge){v,u,0,-c};G.pb(v,etot++);}int Dis[M<<1];bool Vis[M<<1];int Fa[M<<1];int s,tp,t,Ans;queue<int>Q;void MCF(int f){ while(f>0){ while(!Q.empty())Q.pop(); memset(Dis,63,sizeof(Dis)); Dis[s]=0,Q.push(s); while(!Q.empty()){ int A=Q.front();Q.pop(); Vis[A]=0; LREP(i,A,G){ Edge e=E[G[i]]; if(!e.w)continue; int B=e.v; if(Dis[B]>Dis[A]+e.c){ Dis[B]=Dis[A]+e.c; Fa[B]=G[i]; if(!Vis[B])Q.push(B),Vis[B]=1; } } } if(Dis[t]==INF)break; int x=t,Dec=f; while(x!=s){ chkmin(Dec,E[Fa[x]].w); x=E[Fa[x]].u; } x=t; while(x!=s){ E[Fa[x]].w-=Dec,E[Fa[x]^1].w+=Dec; Ans+=Dec*E[Fa[x]].c; x=E[Fa[x]].u; } f-=Dec; }}int D[M],Tim[M],Cnt[M],Mx[M];int main(){ Rd(n),Rd(m),Rd(k); REP(i,1,n)Rd(D[i]); REP(i,0,m){ int t,a,b; Rd(t),Rd(a),Rd(b); Cnt[b]++; chkmax(Mx[a],t); Ans-=t; } REP(i,1,n) Tim[i+1]=max(Tim[i],Mx[i])+D[i]; REP(i,1,n+1) Ans+=Cnt[i]*Tim[i]; s=0,t=(n<<1)+4,tp=t-1; Add_Edge(tp,t,k,0); REP(i,1,n+1) Add_Edge(i,i+n,max(0,Tim[i]-Mx[i]),0); REP(i,2,n+1) Add_Edge(i-1+n,i,INF,-Cnt[i]); REP(i,1,n+1) Add_Edge(i,tp,INF,0); REP(i,1,n) Add_Edge(s,i+n,D[i],0); MCF(k); printf("%d\n",Ans); return 0;}
- 2017-10-17离线赛
- 2017-10-17离线赛总结
- 2017-10-10离线赛
- 2017-10-07离线赛
- 2017-10-09离线赛
- 2017-10-06离线赛
- 2017-10-12离线赛
- 2017-10-15离线赛
- 2017-10-16离线赛
- 2017-10-18离线赛
- 2017-10-10离线赛总结
- 2017-10-3离线赛小结
- 2017-10-4离线赛总结
- 2017-10-6离线赛总结
- 2017-10-7离线赛题解
- 2017-10-7离线赛总结
- 2017-10-8离线赛总结
- 2017-10-9离线赛总结
- js == 与 === 的区别
- jQuery Miscellaneous
- 使用npm安装appium
- hadoop启动就出现 WARN util.NativeCodeLoader:... using builtin的解决方法
- Intent中addFlags()和SetFlags()的区别和详解
- 2017-10-17离线赛
- CS K Consequal 栈+模拟
- SpringBoot(六):过滤器和拦截器
- Tensorflow官网lstm例子
- 分布式Java应用---实现系统间的通信
- c#子线程与主线程之间的通信
- Android高性能编程
- Python 基础语法笔记1
- Window追踪系统端口由那个应用占用的方法