zoukankan      html  css  js  c++  java
  • NOIP2011提高组day2

    NOIP 2011 提高组 Day 2

    T1 :

    题意:

             这道题题意很显然,方法就是利用数学中的二项式定理 : ( x + y ) ^ n = C ( i , n ) * x ^ i * y ^ ( n - i ),i ∈ [ 0 , n ],所以求x ^ n * y ^ m的系数,就是求C( n , k ) * a ^ n * b ^ m再模上10007,注意求C( n , k ) % mod时要求逆元。

    代码:

     

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    
    const int mod = 10007;
    
    long long fac, vfac, vvfac, facc, M;
    long long a, b, k, n, m;
    
    long long exgcd(long long a1, long long b1, long long &x, long long &y) {
      if (b1 == 0) {
          x = 1;
          y = 0;
          return b1;
      } else {
          long long x0, y0;
          long long dd = exgcd(b1, a1 % b1, x0, y0);
          x = y0;
          y = x0 - (a1 / b1) * y0;
          return dd;
      }
    }
    
    long long rv(long long i, long long mo) {
      long long x, y;
      exgcd(i, mo, x, y);
      return (x % mo + mo) % mo;
    }
    
    int main() {
      freopen("factor.in", "r", stdin);
      freopen("factor.out", "w", stdout);
      scanf("%I64d%I64d%I64d%I64d%I64d", &a, &b, &k, &n, &m);
      fac = 1;facc = 1;M = 1;
      for (int i = 1; i <= k; i++) M = M * i % mod;
      for (int i = 1; i <= n; i++) fac = fac * i % mod;
      for (int i = 1; i <= m; i++) facc = facc * i % mod;
      vfac = rv(fac, mod);
      vvfac = rv(facc, mod);
      long long w = (M % mod * vfac % mod * vvfac % mod) % mod;
      long long l = 1, r = 1;
      for (int i = 1; i <= n; i++) l = l * a % mod;
      for (int i = 1; i <= m; i++) r = r * b % mod;
      printf("%I64d
    ", (l % mod * r % mod * w % mod) % mod);
      return 0;
    }
    View Code

     

    T2 :

    题意:

            不难想到这道题求W要用到二分答案,二分的条件也不难想,注意求L到R中有多少个满足W[ i ] >= W的时候可以借助前缀和。

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    
    const int N = 200001;
    
    const long long INF = 1e15 + 1;
    
    long long n, m, S, ans = INF, Y;
    long long w[N], v[N], ll[N], rr[N], sum[N], cnt[N];
    
    bool check(long long x) {
      memset(sum, 0, sizeof(sum));
      memset(cnt, 0, sizeof(cnt));
      Y = 0;
      for (int i = 1; i <= n; i++) {
          if (w[i] >= x) sum[i] = sum[i - 1] + v[i], cnt[i] = cnt[i - 1] + 1;
          else sum[i] = sum[i - 1], cnt[i] = cnt[i - 1];
      }
      for (int i = 1; i <= m; i++)
          Y += (cnt[rr[i]] - cnt[ll[i] - 1]) * (sum[rr[i]] - sum[ll[i] - 1]);
      if (abs(Y - S) <= ans) {
          ans = abs(Y - S);
          return true;
      }
      return false;
    }
    
    int main() {
      freopen("qc.in", "r", stdin);
      freopen("qc.out", "w", stdout);
      scanf("%I64d%I64d%I64d", &n, &m, &S);
      long long ma = -1;
      for (int i = 1; i <= n; i++) {
          scanf("%I64d%I64d", &w[i], &v[i]);
          if (w[i] > ma) ma = w[i];
      }
      for (int i = 1; i <= m; i++) scanf("%I64d%I64d", &ll[i], &rr[i]);
      long long lf = 0, rg = ma;
      while (lf != rg) {
          long long mid = (lf + rg) >> 1;
          if (check(mid) && Y <= S) rg = mid;
          if (check(mid) && Y > S) lf = mid + 1;
          if (!check(mid) && Y <= S) rg = mid;
          if (!check(mid) && Y > S) lf = mid + 1;
      }
      int mid = (lf + rg) >> 1;
      check(mid);
      printf("%I64d
    ", ans);
      return 0;
    }
    View Code

    T3 :

    题意:

              这道题要求的是乘客的总旅行时间最短,不难想到要让每一个乘客旅行时间都最短,所以我们想到可以用贪心算法来求解,所以现在的问题是,我们要怎么使用这些氮气瓶?我们应该给哪些段加速?

            首先,如果有这样的一段路,观光车比下一个站点最晚到的一个人还要到得晚,很显然我们该使用加速器了;其次,如果有很多段这样的路段,我们便选择对结果影响最大的一段,就是在下一站下车人数最多的那一段,这样一直找下去,直到氮气用尽或者是不存在这样的路段。

    需要用到的数组:

    latest[ i ]:站点i乘客最晚到的时间;

    arrive[ i ]:观光车最晚到i站点的时间;

    next[ i ]:离第i个站点最近的站点满足latest[ i ] >= arrive[ i ](意思就是说从i到next[ i ] - 1的路段都满足观光车到得比游客晚);

    sum[ i ]:前i个站中下车的人数;

    这是网上找的有批注版的,便于理解:

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    int n,m,k;
    int Di[1005];
    int t[10005],a[10005],b[10005];
    int arrive[1005],latest[1005];
    int sum[1005],next[1005];
    int minn,sta;
    int ans;
    int maxl;
    int main()
    {
        freopen("bus.in","r",stdin);
        freopen("bus.out","w",stdout);
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i<=n-1;i++)
        scanf("%d",&Di[i]);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&t[i],&a[i],&b[i]);
            sum[b[i]]++;
            if(t[i]>latest[a[i]])latest[a[i]]=t[i];
        }
        //前缀累加和
        for(int i=2;i<=n;i++)
        sum[i]+=sum[i-1];
        while(1)
        {
            //每次更新距离后(用了加速器)都要更新arrive[] 
            arrive[1]=0;
            for(int i=2;i<=n;i++)
            arrive[i]=max(arrive[i-1],latest[i-1])+Di[i-1];
            //且要更新next[],因为用了加速器后,有些点是不满足区间条件
            next[n]=n;
            for(int i=n-1;i>=1;i--)
            {
                //满足条件区间连续  1(*)  2  3(*) 4(*)  5(*) 6  7(*) 8 
                // 3---next[3]-1  3      6  6      6       6    8   8     8                             
                next[i]=next[i+1];
                if(arrive[i+1]<=latest[i+1])//第i+1个点不满足
                next[i]=i+1;
            }
                //贪心需找区间
                maxl=1;
                while(!Di[maxl]&&maxl<=n-1)
                ++maxl;
                if(maxl==n||k==0)break;
                //寻找最优区间
                //i+1--next[i]-1,sum[next[i]]-sum[i]=i+1--
                for(int i=maxl+1;i<=n-1;i++)
                if(Di[i]&&sum[next[maxl]]-sum[maxl]<sum[next[i]]-sum[i])
                maxl=i;
                if(sum[next[maxl]]-sum[maxl]==0)break;//后面已无乘客
                int dd=100005;
                for(int i=maxl+1;i<=next[maxl]-1;i++)
                dd=min(dd,arrive[i]-latest[i]);//最小时间差,乘客先到,汽车后到
                dd=min(dd,k);//这段区间中使用加速器,所有乘客都受益,所以不存在人数最多相同区间
                dd=min(dd,Di[maxl]);
                k-=dd;//区间没人都受益,受益总和确定
                Di[maxl]-=dd;
        } 
        //此时所以bus都比乘客先到达 
        for(int i=1;i<=m;i++)
        ans+=abs(arrive[b[i]]-t[i]);//防止没有加速器 ,可能为负
        cout<<ans<<endl;
        return 0;
    }
    View Code

    这是自己写的:

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    
    const int N = 10001;
    
    int t[N], a[N], b[N], latest[N], arrive[N], d[N], next[N], sum[N];
    int n, m, k, ans;
    
    int main() {
      freopen("bus.in", "r", stdin);
      freopen("bus.out", "w", stdout);
      scanf("%d%d%d", &n, &m, &k);
      for (int i = 1; i <= n - 1; i++) scanf("%d", &d[i]);
      for (int i = 1; i <= m; i++) {
          scanf("%d%d%d", &t[i], &a[i], &b[i]);
          if (t[i] > latest[a[i]]) latest[a[i]] = t[i];
          sum[b[i]]++;
      }
      
      for (int i = 1; i <= n; i++) sum[i] += sum[i - 1];
      
      while (1) {
          int maxl = 1;
          arrive[1] = 0;
          
        for (int i = 2; i <= n; i++)
            arrive[i] = max(arrive[i - 1], latest[i - 1]) + d[i - 1];
          
        next[n] = n;
        for (int i = n - 1; i; i--) {
            next[i] = next[i + 1];
            if (arrive[i + 1] <= latest[i + 1]) next[i] = i + 1;
          }
          
        while (!d[maxl] && maxl <= n - 1) maxl++;
          if (maxl == n || k == 0) break;
          
        for (int i = maxl + 1; i <= n - 1; i++)
            if (d[i] && sum[next[maxl]] - sum[maxl] < sum[next[i]] - sum[i]) maxl = i;
          if (sum[next[maxl]] - sum[maxl] == 0) break;
          
        int least = 1e8 + 7;
          for (int i = maxl + 1; i <= next[maxl] - 1; i++)
            least = min(least, arrive[i] - latest[i]);
          least = min(least, k);
          least = min(least, d[maxl]);
          k -= least;
          d[maxl] -= least;
      }
      for (int i = 1; i <= m; i++) ans += (arrive[b[i]] - t[i]);
      printf("%d", ans);
      return 0;
    }
    View Code
  • 相关阅读:
    自学Linux Shell14.3-创建临时文件
    自学Linux Shell14.2-在脚本中使用其他文件描述符
    自学Linux Shell14.1-理解输入输出
    自学Linux Shell13.3-获得用户输入(read命令)
    自学Linux Shell13.2-选项处理(主要getopt、getopts命令)
    自学Linux Shell13.1-命令行参数
    自学Linux Shell12.8-循环实例
    自学Linux Shell12.7-控制循环break、continue命令
    自学Linux Shell12.6-嵌套循环for命令
    自学Linux Shell12.5-while、until命令
  • 原文地址:https://www.cnblogs.com/ganster/p/8833209.html
Copyright © 2011-2022 走看看