• 2017.7.7 C组总结


    NO.1

    题目描述:
    给定一个长度为N的序列a,对于每一个数都可选或不选,把选出的数有序组成一个新的序列b,使b序列的“和谐数”最大。
    一个序列的和谐数如下定义:对于位置i,如果第奇数次选的则加上bi,偶数次选的则减去bi
    注意:新的序列b必须是从左到右依次在a序列选择的,即不能打乱顺序。

    思路:DP
    设f[i,0/1]表示第i个位置选(为0)或不选(为1)的“和谐数”最大
    状态转移方程为:
    f[i,0]=max(f[i-1,0],f[i-1,1]+a[i])
    f[i,1]=max(f[i-1,1],f[i-1,0]-a[i])
    用了DP,妈妈再也不用担心我不会AC

    代码:

    uses math;
    var n,i,x:longint;
        f:array[0..10000001,0..1]of int64;
    begin
      assign(input,'a.in');
      assign(output,'a.out');
      reset(input);
      rewrite(output);
      readln(n);
      for i:=1 to n do
        begin
          read(x);
          f[i,1]:=max(f[i-1,1],f[i-1,0]-x);
          f[i,0]:=max(f[i-1,0],f[i-1,1]+x);
        end;
      write(max(f[n,1],f[n,0]));
      close(input);
      close(output);
    end.
    

    NO.2

    题目描述:
    ProKing来到了家里,忽然发现桌台上有n1个玩偶,每个玩偶上有一个对应的值,而在桌台下也有n2个玩偶,每个玩偶上也有一个对应的值,现在,proking想知道台上的玩偶的默契值除以台下玩偶的默契值得到的既约分数(既约分数就是分子分母最大公约数为1的分数)
    默契值定义为所有玩偶的权值的乘积.

    20%思路:暴力
    直接将两个序列乘起来,再用辗转相除法求最大公因数

    60%思路:高精度
    可以使用高精度,把两个序列两两去除公因数,时间复杂度O(n^2)

    100%思路:高精度+筛素数+压位
    先用zs[i]来存i的最小质因数
    然后我们对每个序列开一个数组s[i,j]为第j序列拥有i质因数的个数,那么循环枚举a[i,j]的最小质因数(zs[a[i,j]),求出除完最小质数后的数(a[i,j]-a[i,j] div zs[a[i,j]]),再求除后的数的最小质因数……
    到这里,我们求出了每个序列分解质因数后的每个质因数所拥有的质数,那么就去重!!!
    去重分三种情况:
    ①s[i,1]>s[i,2](也就是第一个序列拥有i的数量比第二个序列多),那么s[i,1]-=s[i,2] s[i,2]=0
    ②s[i,2]>s[i,1](第一个序列拥有i的数量比第二个序列少),那么s[i,2]-=s[i,1] s[i,1]=0
    ③s[i,1]=s[i,2](第一个序列拥有i的数量等于第二个序列拥有i的数量),那么s[i,1]=s[i,2]=0
    这样做完,两个序列就必须是互质的
    然后,就用高精度乘法
    因为只用高精度乘法,是会超时的,所以就要用压位
    所谓压位,就是将原本存一位的a[i],改成存多位
    那么压位很简单实现
    还有一个细节,就是在压位输出时,一般会将首位的0省略不输,那么就要加一个处理,将0位补齐(Tips:第一位不用补0)

    代码:

    const max=2300;
          mo=100000000;
    var n:array[1..2]of int64;
        a,s,l:array[0..100101,1..2]of int64;
        x,z,y:int64;
        i,j,k:longint;
        zs:array[0..12624]of int64;
    
    
    procedure zxs;
    var i,x:longint;
    begin
      for i:=2 to 10000 do
        begin
          x:=0;
          for j:=2 to trunc(sqrt(i)) do
            if (i mod j=0) then
              begin
                zs[i]:=j; x:=j;
                break;
              end;
          if x=0 then zs[i]:=i;
        end;
    end;
    
    begin
      assign(input,'count.in');
      assign(output,'count.out');
      reset(input);
      rewrite(output);
      read(n[1]);
      for i:=1 to n[1] do read(a[i,1]);
      readln;
      read(n[2]);
      for i:=1 to n[2] do read(a[i,2]);
      zxs;
      for i:=1 to 2 do
        for j:=1 to n[i] do
          begin
            x:=a[j,i];
            while x>1 do
              begin
                inc(s[zs[x],i]);
                x:=x div zs[x];
              end;
          end;
      for i:=2 to 10000 do
        if (s[i,1]>0)and(s[i,2]>0) then
          if (s[i,1]>s[i,2]) then begin s[i,1]:=s[i,1]-s[i,2]; s[i,2]:=0; end
                             else begin s[i,2]:=s[i,2]-s[i,1]; s[i,1]:=0; end;
      l[max,1]:=1; l[max,2]:=1;
      for i:=1 to 2 do
        for j:=2 to 10000 do
          begin
            z:=s[j,i];
            while z>0 do
              begin
                dec(z);
                for k:=2 to max do l[k,i]:=l[k,i]*j;
                for k:=max downto 2 do
                  if l[k,i]>9 then
                    begin
                      l[k-1,i]:=l[k-1,i]+l[k,i] div mo;
                      l[k,i]:=l[k,i] mod mo;
                    end;
              end;
          end;
      x:=0;
      for i:=1 to 2 do
        begin
          for j:=0 to max do
            if l[j,i]>0 then
              begin
                x:=j;
                break;
              end;
          write(l[x,i]);
          for j:=x+1 to max do
            begin
              y:=l[j,i]; z:=0;
              if y=0 then y:=1;
              while y<mo do
                begin
                  y:=y*10;
                  z:=z+1;
                end;
              for k:=2 to z do write('0');
              write(l[j,i]);
            end;
          write(' ');
        end;
      close(input);
      close(output);
    end.

    NO.3

    题目描述:
    给定一个长度为n的序列a,试求出对于序列a的每一个前缀的终极数x,使得

    这里写图片描述
    最小,试求出终极数t(如若有多个终极数t,只需输出最小的那个)

    思路:堆维护+快排
    这题的主要思路就是就中位数
    堆有两个堆一个是大根堆,一个是小根堆,其实小根堆的堆顶就是中位数
    这个问题就转移为维护一个堆
    维护一个堆有三种情况:
    ①将大根堆从大到小排序
    ②将小根堆从小到大排序
    ③如果,大根堆顶大于小根堆顶,就将大根堆顶和小根堆顶交换,交换后的大根堆和小根堆都要进行重新排序
    那么每一次的小根堆顶就是x终极数
    最后再快排终极数,求出中位数即可AC

    代码:

    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    using namespace std;
    int x1,x2,a[1000001]={0},big[1000001]={0},small[1000001],x[1000001],i,t,n;
    void temp1(int x)
    {
         while ((x>1)&&(small[x]<small[x/2]))
         {
               t=small[x];small[x]=small[x/2];small[x/2]=t;
               x=x/2;
         }
    }
    void temp2(int x)
    {
         while ((x>1)&&(big[x]>big[x/2]))
         {
               t=big[x];big[x]=big[x/2];big[x/2]=t;
               x=x/2;
         }
    }
    void doit1(int x)
    {
         int y;
         while (((x*2<=x1)&&(small[x*2]<small[x]))||(((x*2+1)<=x1)&&(small[x*2+1]<small[x])))
         {
               y=x*2;
               if ((x*2+1<=x1)&&small[x*2+1]<small[x*2]) y=x*2+1;
               t=small[y];small[y]=small[x];small[x]=t;
               x=y;
         }
    }
    void doit2(int x)
    {
         int y;
         while (((x*2<=x2)&&(big[x*2]>big[x]))||(((x*2+1)<=x2)&&(big[x*2+1]>big[x])))
         {
               y=x*2;
               if (x*2+1<=x2&&big[x*2+1]>big[x*2]) y=x*2+1;
               t=big[y];big[y]=big[x];big[x]=t;
               x=y;
         }
    }
    void qsort(int l,int r)
    {
         int i=l,j=r,mid=x[(l+r)/2];
         if (l>=r) return;
         do
         {
                   while(x[i]<mid) i++;
                   while(x[j]>mid) j--;
                   if (i<=j)
                   {
                            t=x[i];x[i]=x[j];x[j]=t;
                            i++;j--;
                   }
         }
         while (i<=j);
         qsort(l,j);
         qsort(i,r);
    }
    int main()
    {
        freopen("c.in","r",stdin);
        freopen("c.out","w",stdout);
        scanf("%d",&n);
        x1=0;
        x2=0;
        for (int i=1;i<=n;i++) 
        {
            scanf("%d",&a[i]);
            if (i%2==1)
            {
                          x1++;
                          small[x1]=a[i];
                          temp1(x1);
                          if (small[1]<big[1])
                          {
                                              t=small[1];small[1]=big[1];big[1]=t;
                                              doit1(1);
                                              doit2(1);
                          } 
            }
            else 
            {
                          x2++;
                          big[x2]=a[i];
                          temp2(x2);
                          if (small[1]<big[1])
                          {
                                              t=small[1];small[1]=big[1];big[1]=t;
                                              doit1(1);
                                              doit2(1);
                          } 
            }
            x[i]=small[1]; 
        }
        qsort(1,n);
        printf("%d",x[n/2]);
        fclose(stdin);
        fclose(stdout);
        return 0;
    }

    NO.4

    题目描述:给定一个0-1串,请找到一个尽可能长的子串,其中包含的0与1的个数相等。

    思路:前缀和+贪心
    如果设遇’0’+1,遇’1’-1
    那么如果在前后找到有相等的数值时,这两个中间的序列必定是符合的!(长度就是x[i]-x[j])
    那么为了减少时间复杂度,就可以用贪心思想,记录出现这个数的最前和最后
    循环一遍求出最长的长度

    代码:

    var s:ansistring;
        i,ans,j,min,max,x:longint;
        min1,max1:array[-1000001..1000001]of longint;
    begin
      assign(input,'string.in');
      reset(input);
      assign(output,'string.out');
      rewrite(output);
      fillchar(min,sizeof(min1),127);
      min1[0]:=0;
      readln(s);
      min:=maxlongint;
      x:=0;
      max:=0;
      for i:=1 to length(s) do
        if s[i]='1' then
          begin
            inc(x);
            if x>max then max:=x;
            if x<min then min:=x;
            if i<min1[x] then min1[x]:=i;
            if i>max1[x] then max1[x]:=i;
          end
        else
          begin
            dec(x);
            if x>max then max:=x;
            if x<min then min:=x;
            if i<min1[x] then min1[x]:=i;
            if i>max1[x] then max1[x]:=i;
          end;
      for i:=min to max do
        if ans<max1[i]-min1[i] then ans:=max1[i]-min1[i];
      write(ans);
      close(input);
      close(output);
    end.
    
  • 相关阅读:
    C#编程的最佳工具
    Visual Studio Code搭建python开发环境
    Python打包文件夹的方法小结(zip,tar,tar.gz等)
    【转】python文件和目录操作方法大全(含实例)
    win764位系统上让32位程序能申请到4GB内存方法
    [转]bigbluebutton中文社区 / 开放API / bbb API
    [转]26款 网络会议/视频会议开源软件
    【转】用python比对数据库表数据的脚本
    plsql查询数据库-中文显示问号问题
    plsql 使用desc命令提示invalid sql statement
  • 原文地址:https://www.cnblogs.com/Comfortable/p/8412273.html
Copyright © 2020-2023  润新知