zoukankan      html  css  js  c++  java
  • 2017.7.14 C组总结

    NO.1

    题目描述:有n个长方形,给出它的左下角和右上角,求出q个点被多少个长方形覆盖(平行于x轴和y轴)

    思路:差分+前缀和
    这里写图片描述

    代码:

    var n,i,x,y,x1,y1,j,q:longint;
        a,f:array[0..3001,0..3001]of longint;
    begin
      assign(input,'square.in');
      assign(output,'square.out');
      reset(input);
      rewrite(output);
      readln(n);
      for i:=1 to n do
        begin
          readln(x,y,x1,y1);
          inc(a[x,y]);
          inc(a[x1+1,y1+1]);
          dec(a[x1+1,y]);
          dec(a[x,y1+1]);
        end;
      for i:=1 to 3000 do
        for j:=1 to 3000 do
          f[i,j]:=f[i-1,j]+f[i,j-1]-f[i-1,j-1]+a[i,j];
      readln(q);
      for i:=1 to q do
        begin
          readln(x,y);
          writeln(f[x,y]);
        end;
      close(input);
      close(output); 
    end.

    NO.2

    题目描述:给出N个无序不重复的数,再有M个询问,每次询问一个数是否在那N个数中,若在,则ans增加2^K,K为该数在原数列中的位置。由于ans过大,所以只要求你输出ans mod 10^9+7。

    思路:快速幂+排序+二分
    先做一遍快排,为二分作准备
    那么每次读入一个数,就可以二分求出位置
    求2^k次方做一遍快速幂(dalao都说可以不用跑快速幂,在前面预处理就好了)

    代码:

    #include<cstdio>
    #include<iostream>
    using namespace std;
    long long ans,a[100000],x;
    int n,m,l,c[100000];
    void qsort(int l,int r)
    {
        if (l>=r) return;
        int i=l,j=r;
        long long mid=a[(l+r)/2];
        do
        {
            while (a[i]<mid)i++;
            while (a[j]>mid)j--;
            if (i<=j)
            {
                a[0]=a[i];
                a[i]=a[j];
                a[j]=a[0];
                c[0]=c[i];
                c[i]=c[j];
                c[j]=c[0];
                i++; j--;
            }
        }
        while(i<=j);
        qsort(l,j);
        qsort(i,r);
    }
    int find(long long x)
    {
        int l=1,r=n;
        while (l<=r)
        {
            int mid=(l+r)/2;
            if (a[mid]==x) return mid;
            if (a[mid]>x) r=mid-1;
            else l=mid+1;
        }
        return -1;
    }
    long long ksm(int b)
    {
        long long r=1,base=2;
        while(b)
        {
            if(b&1) r=(r*base)%1000000007;
            base=(base*base)%1000000007;
            b>>=1;
        }
        return r;
    }
    int main()
    {
        freopen("sfxx.in","r",stdin);
        freopen("sfxx.out","w",stdout);
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;i++)
        {
            scanf("%lld",&a[i]);
            c[i]=i;
        }
        qsort(1,n);
        for (int i=1;i<=m;i++)  
        {
            scanf("%lld",&x);
            l=find(x);
            if (l!=-1) ans=(ans%1000000007+ksm(c[l])%1000000007)%1000000007;
        }
        printf("%lld",ans);
        fclose(stdin);
        fclose(stdout);
        return 0;
    }

    NO.3

    题目描述:有l回合操作,其中第一回合是给出的,如果上一轮第i列放了棋子,那么这一轮第i列就不能放棋子,但再下一轮可以放,求在满足情况下有多少种放棋子的方案

    思路:状压dp
    设f[i][j]为第i轮状态为j的方案数
    状态转移方程就是f[i][j]=f[i][j]+f[i-1][k](k表示为上个回合可以转换到j的数)
    如果要k满足它可以转换到j,就满足j and k=0(因为and 只有在同一个位上有两个1才肯能有值,题目要没有相邻的棋子,如果=1就满足了)
    那么问题就变成了求j和k的问题
    首先,将第1轮的所有状态(1 shl n-1)设为1
    然后,枚举i(2<=i<=l),枚举j可能到达的状态(1<=j<=1 shl n-1)
    那么就只剩下k了,如果像j那样枚举,只能拿到90%
    100%怎么做呢?
    就用while做, 有两种情况:
    ①j and k=0,那么转移,k++
    ②就是100%的优化,如果j and k<>0 就表示这两轮在有相邻的棋子,那么k=k+j and k就把有相邻的棋子弄没了
    最后的答案就是将读入的数压成十进制x,输出f[l][x]

    代码:

    var  n,l,i,j:longint;
         ans,k,y,x:int64;
         a:array[0..50]of longint;
         f:array[0..50,0..50000]of int64;
    begin
      assign(input,'old.in');
      assign(output,'old.out');
      reset(input);
      rewrite(output);
      readln(n,l);
      y:=0;
      for i:=1 to n do
        begin
          read(a[i]);
          if i=1 then y:=1 else y:=y*2; 
          if a[i]=1 then x:=x+y;
        end;
      for i:=0 to 1 shl n-1 do f[0,i]:=1;
      for i:=1 to l-1 do
        begin
          for j:=0 to 1 shl n-1 do
            begin
              k:=0;
              while (k<=1 shl n-1) do
                begin
                  if (j and k=0) then
                    begin
                      f[i,j]:=(f[i,j]+f[i-1,k])mod 100000007;
                      k:=k+1;
                    end;
                  if (j and k>0) then k:=k+j and k;
                end;
            end;
        end;
      write(f[l-1,x]);
      close(input);
      close(output);
    end.

    NO.4

    题目描述:有n堆,每堆的值不一定相等,现在有两个人,每个人依次取一堆,要剩下m堆,如果最后剩下的值为偶数,则后手赢,不然则先手赢

    思路:数学+模拟
    其实这题就是判断奇偶性,所以只用记录它的奇数个数l1,和偶数个数l2
    还要定义两个变量,l和r表示先手和后手能取多少次
    这题就有五种情况:
    ①双方都不能取(n=m),直接判断奇偶性
    ②如果后手能拿走所有的奇数,那么后手赢(因为只剩下偶数)
    ③如果后手能拿走所有的偶数,并且还剩偶数份,那么后手赢(奇数*偶数=偶数)
    ④如果先手能拿走所有的偶数,并且还剩奇数份,那么先手赢(奇数*奇数=奇数
    ⑤如果都不存在以上情况,直接判断输出

    代码:

    var   n,m,x,l,r,l1,l2,i:longint;
          max:int64;
    begin
      assign(input,'destroy.in');
      assign(output,'destroy.out');
      reset(input);
      rewrite(output);
      while not eof() do
        begin
          readln(n,m);
          l1:=0; l2:=0;
          for i:=1 to n do
            begin
              read(x);
              if x mod 2=1 then inc(l1)
                           else inc(l2);
            end;
          readln;
          max:=l1+2*l2;
          if n=m then
            begin
              if max mod 2=1 then writeln('Earth')
                             else writeln('Three-Body');
            end
          else
            begin
              l:=0; r:=0;
              l:=(n-m+1) div 2;
              r:=(n-m) div 2;
              if (r>=l1)or(r>=l2)and((max-l2-l-r) mod 2=0) then writeln('Three-Body')
              else if (l>=l2)and((max-l2-l-r) mod 2=1) then writeln('Earth')
                   else if l>r then writeln('Earth')
                               else writeln('Three-Body');
            end;
        end;
      close(input);
      close(output);
    end.
  • 相关阅读:
    2021-06-22 总结
    【每日一题】13. 罗马数字转整数
    【每日一题】12. 整数转罗马数字
    【每日一题】1269. 停在原地的方案数
    【每日一题】1310. 子数组异或查询
    【每日一题】1734. 解码异或后的排列
    【每日一题】872. 叶子相似的树
    【每日一题】1482. 制作 m 束花所需的最少天数
    【每日一题】1723. 完成所有工作的最短时间
    【每日一题】1486. 数组异或操作
  • 原文地址:https://www.cnblogs.com/Comfortable/p/8412266.html
Copyright © 2011-2022 走看看