(补题解)Codeforces Round #271 (Div. 2)

前言:最近被线段树+简单递推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\n",p);
31     }

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\n",(s[y]-s[x-1]+mod)%mod);
30         }
31
32     return 0;

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 }

它这里限制了第二重循环的次数,实际上可以第二重循环可以弄到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\n",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 }

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\n",r-l+1-x);
66     }
67     return 0;
68 }

时间: 2024-08-03 15:04:24

(补题解)Codeforces Round #271 (Div. 2)的相关文章

Codeforces Round #271 (Div. 2) D.Flowers DP

D. Flowers We saw the little game Marmot made for Mole's lunch. Now it's Marmot's dinner time and, as we all know, Marmot eats flowers. At every dinner he eats some red and white flowers. Therefore a dinner can be represented as a sequence of several

Codeforces Round #271 (Div. 2) D. Flowers (递推)

题目链接:http://codeforces.com/problemset/problem/474/D 用RW组成字符串,要求w的个数要k个连续出现,R任意,问字符串长度为[a, b]时,字符串的种类有多少. 递推,dp[i]表示长度为i的种类有多少.当i < k的时候 dp[i] = 1 , 当i == k的时候 dp[i] = 2 ,  否则 dp[i] = dp[i - 1] + dp[i - k] . 1 #include <bits/stdc++.h> 2 using name

题解Codeforces Round #595 (Div. 3)(CF1249)

开题1小时(雾)严重影响我的提交以及做题心情..我刚开题就发现有人阿克了.. 实际上这场div3真心简单良心很休闲. A:送分题,先排序,每次枚举一下这个数可以加到哪个集合里,加进去就行. 1 #include<stdio.h> 2 #include<algorithm> 3 #define it register int 4 #define il inline 5 using namespace std; 6 const int N=1000005; 7 int a[N],o[N

Codeforces Round #271 (Div. 2) F.Ant colony(线段树 + 统计区间内某数的个数)

F. Ant colony Mole is hungry again. He found one ant colony, consisting of n ants, ordered in a row. Each ant i (1 ≤ i ≤ n) has a strength si. In order to make his dinner more interesting, Mole organizes a version of «Hunger Games» for the ants. He c

Codeforces Round #271 (Div. 2)

It is lunch time for Mole. His friend, Marmot, prepared him a nice game for lunch. Marmot brought Mole n ordered piles of worms such that i-th pile contains ai worms. He labeled all these worms with consecutive integers: worms in first pile are label

Codeforces Round #271 (Div. 2) A. Keyboard

Our good friend Mole is trying to code a big message. He is typing on an unusual keyboard with characters arranged in following way: qwertyuiop asdfghjkl; zxcvbnm,./ Unfortunately Mole is blind, so sometimes it is problem for him to put his hands acc

Codeforces Round #271 (Div. 2)D(递推,前缀和)

很简单的递推题.d[n]=d[n-1]+d[n-k] 注意每次输入a和b时,如果每次都累加,就做了很多重复性工作,会超时. 所以用预处理前缀和来解决重复累加问题. 最后一个细节坑了我多次: printf("%I64d\n",(s[b]-s[a-1]+mod)%mod); 这句话中加mod万万不能少,因为理论上s[b]-s[a-1]肯定大于0,但是由于两个都是模1000000007以后的结果,那么就不一定了,当s[b]-s[a-1]<0时结果是负的,不是题意中应该输出的结果,所以一

Codeforces Round #271 (Div. 2) D. Flowers (递推 预处理)

We saw the little game Marmot made for Mole's lunch. Now it's Marmot's dinner time and, as we all know, Marmot eats flowers. At every dinner he eats some red and white flowers. Therefore a dinner can be represented as a sequence of several flowers, s

题解——Codeforces Round #508 (Div. 2) T2 (构造)

按照题意构造集合即可 注意无解情况的判断 #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> #include <vector> #include <map> using namespace std; int n,sum; int main(){ scanf("%d",&n); if(n==1){ printf