zoukankan      html  css  js  c++  java
  • Codeforces Round #271 (Div. 2) F ,E, D, C, B, A

    前言:最近被线段树+简单递推DP虐的体无完肤!真是弱!

        A:简单题,照着模拟就可以,题目还特意说不用处理边界

       B:二分查找即可,用lower_lound()函数很好用

     1 #include<string.h>
     2 #include<math.h>
     3 #include<algorithm>
     4 #include<stdio.h>
     5 #include<math.h>
     6 #include<string>
     7 #include<iostream>
     8 using namespace std;
     9 #define N 200005
    10 #define lson l, m, rt<<1
    11 #define rson m+1, r, rt<<1|1
    12 
    13 int a[N],s[N];
    14 int main()
    15 {
    16     int n;
    17     scanf("%d",&n);
    18     for (int i=1;i<=n;i++)
    19         scanf("%d",&a[i]);
    20 
    21     for (int i=1;i<=n;i++)
    22         a[i]+=a[i-1];
    23     int m;
    24     scanf("%d",&m);
    25     while (m--)
    26     {
    27         int x;
    28         scanf("%d",&x);
    29         int p=lower_bound(a+1,a+n+1,x)-a;
    30         printf("%d
    ",p);
    31     }
    View Code

    C:没写,但是是一道比较难处理的模拟题吧,求每个点绕它中轴点顺时针旋转90度,求能形成的最小旋转次数,4^4次,还有面积要大于0这个坑点。

    D:简单DP,居然推到数学公式,真是SB,我们要使连续的字符串里面个W个数为x*k;当时想到求排列组合,以为可以化简,结果自己掉坑里!

         正确做法,定义一维数组,就是求前导和。

       方程:DP[I]=DP[I-1]+DP[I-K];(i>=k);(表示:I不为好的话,和为好的发时的总数)

               DP[I]=DP[I-1];

              s[i]=s[i-1]+DP[I]; (对前i段累加)

            中间有Mod 操作,有很多询问,所以要一次做,然后之间求区间值即可!

     1 #include<bits/stdc++.h>
     2 typedef long long ll;
     3 using namespace std;
     4 
     5 #define mod  1000000007
     6 #define N 100007
     7 int a[N];
     8 ll s[N];
     9 
    10 
    11 int main()
    12 {
    13     int k,t;
    14     scanf("%d%d",&t,&k);
    15     a[0]=1;
    16     for (int i=1;i<N;i++)
    17     {
    18         if (i>=k) {a[i]=a[i-1]+a[i-k];a[i]%=mod;}
    19         else {a[i]=a[i-1];a[i]%=mod;}
    20         
    21         s[i]=s[i-1]+a[i];
    22         s[i]%=mod;
    23         }
    24 
    25     while (t--)
    26     {
    27         int x,y;
    28         scanf("%d%d",&x,&y);
    29         printf("%d
    ",(s[y]-s[x-1]+mod)%mod);
    30         }
    31 
    32     return 0;
    View Code

    E:题目简短,二维可以写出,但会TLE。

    然后看到一个神奇骗AC代码,可以看看

     1 include<bits/stdc++.h>
     2 #define N 111111
     3 using namespace std;
     4 typedef long long ll;
     5 int n;
     6 ll h[N],ans[N],next[N];
     7 ll d;
     8 int main()
     9 {
    10     cin>>n>>d;
    11     for (int i=1;i<=n;i++)
    12     {
    13         cin>>h[i];
    14         ans[i]=1;
    15         next[i]=-1;
    16     }
    17     int mx=1;
    18         int start=n;
    19         for (int i=n;i>=1;i--){
    20         for (int j=i+1;j<=min(i+300,n);j++)
    21         {
    22         if (abs(h[j]-h[i])>=d&&ans[j]+1>ans[i])
    23         {
    24             next[i]=j;
    25             ans[i]=ans[j]+1;
    26         }
    27      }
    28 
    29 
    30      if (ans[i]>mx)
    31      {
    32         mx=ans[i];
    33         start=i;
    34      }
    35    }
    36 
    37    cout<<mx<<endl;
    38    int    i=start;
    39    while (i!=-1)
    40    {
    41        cout<<i<<" ";
    42        i=next[i];
    43    }
    44 
    45    return 0;
    46 }
    View Code

    它这里限制了第二重循环的次数,实际上可以第二重循环可以弄到300,或者更少,数据太弱吧!

    正解:线段树单点跟新+二分!

    分析写到代码里吧!

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 #define lson l, m,rt<<1
     5 #define rson m+1,r,rt<<1|1
     6 #define N 111111
     7 ll h[N],hh[N],k;
     8 int n;
     9 int pre[N],ss[N];
    10 int sum[N<<2];
    11 int dp[N];
    12 
    13 void pushup(int rt)//求区间最大值
    14 {
    15     sum[rt]=max(sum[rt<<1],sum[rt<<1|1]);
    16 }
    17 
    18 
    19 void update(int p,int y,int l,int r,int rt)//单点更新
    20 {
    21 
    22     if (l==r)
    23     {
    24         if (sum[rt]<y) sum[rt]=y;
    25         return;
    26     }
    27     int m=(l+r)>>1;
    28     if (p<=m) update(p,y,lson);
    29     else update(p,y,rson);
    30     pushup(rt);
    31 }
    32 
    33 //询问L,R区间最大值
    34 int query(int L,int R,int l,int r,int rt)
    35 {
    36     if (R<L) return 0;
    37     if (L<=l&&R>=r) return sum[rt];
    38 
    39     int m=(l+r)>>1;
    40     int ret=0;
    41     if (L<=m) ret=query(L,R,lson);
    42     if (m<R) ret=max(ret,query(L,R,rson));
    43     return ret;
    44 }
    45 
    46 int main()
    47 {
    48     scanf("%d%d",&n,&k);
    49     for (int i=1;i<=n;i++)
    50         scanf("%I64d",&h[i]),hh[i]=h[i];
    51     sort(h+1,h+n+1);
    52     int len=0;
    53     for (int i=1;i<=n;i++)
    54     if (h[i]!=h[i-1]) h[++len]=h[i];//排序处理
    55 
    56     int ans=0;
    57     //整体说一下思路
    58     //我们先排序出去重,把每个数据抽象变成一个点,然后维护。
    59     //我们知道DP[I]=MAX(DP[J])+1,abs(h[i]-h[j])>=k;
    60     //于是我们在前面找到h[i]-h[j]>=k中左右区间然后跟新,这应该是线段树+DP的共同点
    61     //对H[J]-H[J]>=K同样处理。
    62     for (int i=1;i<=n;i++)
    63     {
    64         int l=lower_bound(h+1,h+len+1,hh[i]+k)-h;//这里的lower_bound与upper_bound不能弄错
    65         int r=len;
    66         int x=query(l,r,1,len,1);
    67         r=upper_bound(h+1,h+len+1,hh[i]-k)-h;//求出左右区间,这里得多看看
    68         
    69         x=max(x,query(1,r-1,1,len,1));
    70         dp[i]=x+1;
    71         int y=lower_bound(h+1,h+len+1,hh[i])-h;
    72         update(y,dp[i],1,len,1);
    73         ans=max(ans,dp[i]);
    74     }
    75     printf("%d
    ",ans);
    76     ll hp=1e17;
    77     int inx=0;//输出的处理
    78     for (int i=n;i>=1;i--)
    79     {
    80         if (ans==0) break;
    81         if (dp[i]==ans&&abs(hh[i]-hp)>=k)
    82         {
    83             hp=hh[i];
    84             ans--;
    85             ss[++inx]=i;
    86 
    87         }
    88     }
    89     for (int i=inx;i>=1;i--) printf("%d ",ss[i]);
    90     return 0;
    91 }
    View Code

    F:可以这么认为求出(L,R)区间的GCD,然后问(L,R)有多少个值=GCD();

       线段树求GCD()不是难点,

     求一段区间有多少值=GCD();要用到神奇处理

     int x=upper_bound(a+1,a+n+1,mp(mi,r))-lower_bound(a+1,a+n+1,mp(mi,l));

    这里用pair()容器,可以知道有多少个

     1 #include<bits/stdc++.h>
     2 
     3 #define lson l,m,rt<<1
     4 #define rson m+1,r, rt<<1|1
     5 #define N 111111
     6 
     7 #define mp make_pair
     8 using namespace std;
     9 pair<int,int>a[N];
    10 
    11 int s[N<<2];
    12 
    13 int gcd(int x,int y)
    14 {
    15     if (y==0) return x;
    16     if (x%y==0) return y;
    17     return gcd(y,x%y);
    18     }
    19 
    20 void pushup(int rt)
    21 {
    22     s[rt]=gcd(s[rt<<1],s[rt<<1|1]);
    23     }
    24 
    25 void build(int l,int r,int rt)
    26 {
    27     if (l==r)
    28     {
    29        s[rt]=a[l].first;
    30        return;
    31     }
    32     int m=(l+r)>>1;
    33     build(lson);
    34     build(rson);
    35     pushup(rt);
    36 }
    37 
    38 int query(int L,int R,int l,int r,int rt)
    39 {
    40     if (L<=l&&R>=r)
    41         return s[rt];
    42     int m=(l+r)>>1;
    43     int ret=0;
    44     if (L<=m)  ret=gcd(ret,query(L,R,lson));
    45     if (R>m)   ret=gcd(ret,query(L,R,rson));
    46     return ret;
    47 }
    48 
    49 int main()
    50 {
    51     int n;
    52     scanf("%d",&n);
    53     for (int i=1;i<=n;i++) scanf("%d",&a[i].first),a[i].second=i;
    54     build(1,n,1);
    55     sort(a+1,a+n+1);
    56 
    57     int Q;
    58     scanf("%d",&Q);
    59     while (Q--)
    60     {
    61         int l,r;
    62         scanf("%d%d",&l,&r);
    63         int mi=query(l,r,1,n,1);
    64         int x=upper_bound(a+1,a+n+1,mp(mi,r))-lower_bound(a+1,a+n+1,mp(mi,l));
    65         printf("%d
    ",r-l+1-x);
    66     }
    67     return 0;
    68 }
    View Code
  • 相关阅读:
    overlapped
    overlapped编程
    Oracle DB 使用子查询来解决查询
    OCP-1Z0-051-V9.02-132题
    OCP-1Z0-051-V9.02-131题
    OCP-1Z0-051-V9.02-130题
    OCP-1Z0-051-V9.02-129题
    OCP-1Z0-051-V9.02-128题
    OCP-1Z0-051-V9.02-127题
    OCP-1Z0-051-V9.02-126题
  • 原文地址:https://www.cnblogs.com/forgot93/p/4013017.html
Copyright © 2011-2022 走看看