NOIP 2011 提高组合集
D1 T1 铺地毯
模拟,题目让你干啥你就干啥
#include <iostream> #include <cstdio> using namespace std; int x[100010],y[100010],dx[100010],dy[100010]; int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d%d%d%d",&x[i],&y[i],&dx[i],&dy[i]); int a,b; scanf("%d%d",&a,&b); int r=-1; for(int i=1;i<=n;i++) { if(a>=x[i]&&a<=x[i]+dx[i]&&b>=y[i]&&b<=y[i]+dy[i]) r=i; } printf("%d ",r); return 0; }
D1 T2 选择客栈
做的时候好像麻烦了。我的做法是对于一个可以当接头地点的店,考虑它的贡献。为了避免算重,我们令它是左端点往右走的第一个满足条件的店。说是第一个满足条件,但是不一定非要在这里吃。
然后根据这个节点的往右走第一个不满足的,乘以右边的所有点,更新答案。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define N 200010 #define M 60 using namespace std; typedef long long ll; int a[N],b[N],f[N][M]; int main() { int n,k,p; cin >> n >> k >> p ; for(int i=1;i<=n;i++) scanf("%d%d",&a[i],&b[i]); for(int i=n;i>=0;i--) { for(int j=0;j<k;j++) { f[i][j]=f[i+1][j]; if(a[i]==j&&i) f[i][j]++; } } // for(int i=1;i<=n;i++) printf("%d %d ",f[i][0],f[i][1]); int bfr=0; ll ans=0; for(int i=1;i<=n;i++) { if(b[i]>p) continue; for(int j=0;j<k;j++) { ans+=1ll*(f[bfr+1][j]-f[i+1][j])*f[i+1][j]; // ans+=(f[bfr+1][j]-f[i][j]); } ans+=f[bfr+1][a[i]]-f[i][a[i]]; bfr=i; } printf("%lld ",ans); return 0; }
D1 T3 Mayan游戏
挖坑代填
D2 T1 计算系数
知道二项式定理这题是sb题。
#include <bits/stdc++.h> #define mod 10007 using namespace std; typedef long long ll; ll quick_power(ll a,ll b) { ll ans=1; while(b) { if(b&1) ans=(ans*a)%mod; b>>=1; a=(a*a)%mod; } return ans; } ll before[1010]; int main() { before[0]=1; for(ll i=1;i<=1000;i++) { before[i]=before[i-1]*i%mod; } ll a,b,k,n,m; cin >> a >> b >> k >> n >> m ; // a%=mod,b%=mod; printf("%lld ",quick_power(a,n)%mod*quick_power(b,m)%mod*before[k]%mod *(quick_power(before[n],mod-2)%mod*quick_power(before[k-n],mod-2)%mod)%mod); }
D2 T2 聪明的质检员
考虑二分,然后直接暴力枚举验证即可,时间复杂度为O(logn(n+m))。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define N 200010 using namespace std; typedef long long ll; int n,m; ll S; int f[N]; ll g[N]; ll L[N],R[N],w[N],v[N]; inline char nc() {static char *p1,*p2,buf[100000]; return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;} ll rd() {ll x=0; char c=nc(); while(!isdigit(c)) c=nc(); while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=nc(); return x;} ll check(int x) { f[0]=0,g[0]=0; for(int i=1;i<=n;i++) { f[i]=f[i-1]; g[i]=g[i-1]; if(w[i]>=x) f[i]++,g[i]+=v[i]; } ll ans=0; for(int i=1;i<=m;i++) ans+=1ll*(g[R[i]]-g[L[i]-1])*(f[R[i]]-f[L[i]-1]); return ans; } int main() { n=rd(),m=rd(),S=rd(); ll maxn=0; for(int i=1;i<=n;i++) w[i]=rd(),v[i]=rd(),maxn=max(maxn,v[i]); for(int i=1;i<=m;i++) L[i]=rd(),R[i]=rd(); ll l=0,r=maxn+1; ll minn=1000000000000000000ll; while(l<r) { int mid=(l+r)>>1; ll now=check(mid); minn=min(minn,abs(now-S)); if(now<S) r=mid; else l=mid+1; } printf("%lld ",minn); return 0; }
D2 T3 观光公交
我们考虑每一个加速器的利与弊即可。如果到达了之后还是需要等,我们减少了以等的那个节点为终点的乘客的时间。如果到达了直接走,我们节省了所有人的时间。所以我们可以贪心地做这个事情。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define N 20010 using namespace std; struct node { int start,arrive,target; }a[N]; int n,m,K,ans; int f[N],Time[N],g[N],dist[N],sum[N]; int main() { scanf("%d%d%d",&n,&m,&K); for(int i=1;i<n;i++) scanf("%d",&dist[i]); for(int i=1;i<=m;i++) { scanf("%d%d%d",&a[i].arrive,&a[i].start,&a[i].target); f[a[i].start]=max(f[a[i].start],a[i].arrive); sum[a[i].target]++; } for(int i=2;i<=n;i++) sum[i]+=sum[i-1]; Time[1]=0; for(int i=2;i<=n;i++) Time[i]=max(Time[i-1],f[i-1])+dist[i-1]; for(int i=1;i<=m;i++) ans+=Time[a[i].target]-a[i].arrive; while(K) { g[n]=n; g[n-1]=n; for(int i=n-2;i;i--) { if(Time[i+1]<=f[i+1]) g[i]=i+1; else g[i]=g[i+1]; } int Max=0,j; for(int i=1;i<=n;i++) if(sum[g[i]]-sum[i]>Max&&dist[i]>0) Max=sum[g[i]]-sum[i],j=i; if(!Max) break; ans-=Max; dist[j]--; K--; Time[1]=0; for(int i=2;i<=n;i++) Time[i]=max(Time[i-1],f[i-1])+dist[i-1]; } cout << ans << endl ; return 0; }