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\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 }