[考试反思]0916csp-s模拟测试44:可笑

出现了有史以来第一个3首杀AK啊。。。然而跟我没有丝毫关系

(曾经还是有一次考试差点就有那么一点关系的。。。)

然而反正我考得很水就是了。不是很垃圾,而是很水。

这套题是真的水。。。

 

T1不会证复杂度,但是A掉了,数据很难造所以对拍基本上是白打了。。。

复杂度是对的。数据很水。

T2的话想了挺久,想到要分两种情况讨论,一种简单贪心即可,另一种比较复杂。

考场上没有发现单调性于是复杂度n2了。

但是数据水的过分只要打出来第一种就行了,极其荒谬,样例都不过就能A。

当然我两种情况都打了,复杂度也没被卡。

%%%kx只打了复杂的第二种情况,但是垃圾测试点之留下了他爆搜的10分,RP++;

T3暴力dp对了但是没读入。不知怎么的反正过样例了

我自己都要笑死了。。。。

如果读入了就是230了rank2呢。。。哪里有什么如果

一定要手模样例,尤其在出题人只给了一个小样例的时候

 

T1:D

比较简单。做成了STL题。

用vector维护每一个因数连续出现的最早位置。用map维护每一个因数在vector里的下标。

打麻烦了。

复杂度O(n log2n)

 1 #include<cstdio>
 2 #include<vector>
 3 #include<map>
 4 using namespace std;
 5 vector<int>v[2],p[2];
 6 map<int,int>m;
 7 int gcd(int a,int b){while(b)b^=a^=b^=a%=b;return a;}
 8 int n,a[100005];long long ans;
 9 int main(){//freopen("1.in","r",stdin);freopen("co.out","w",stdout);
10     scanf("%d",&n);
11     for(int i=1;i<=n;++i)scanf("%d",&a[i]);
12     v[1].push_back(a[1]);p[1].push_back(1);ans=a[1];
13     for(int i=2;i<=n;++i){
14         for(int j=0;j<v[i&1^1].size();++j){
15             int G=gcd(a[i],v[i&1^1][j]),M=m[G],P=p[i&1^1][j];
16             if(M)P=p[i&1][M-1]=min(p[i&1][M-1],P);
17             else v[i&1].push_back(G),p[i&1].push_back(P),m[G]=v[i&1].size();
18             ans=max(ans,1ll*G*(i-P+1));
19         }
20         ans=max(ans,1ll*a[i]);
21         if(m.find(a[i])==m.end())v[i&1].push_back(a[i]),p[i&1].push_back(i);
22         m.clear();
23         v[i&1^1].clear();p[i&1^1].clear();
24     }
25     printf("%lld\n",ans);
26 }
View Code

思路积累:

  • 相邻项取gcd以取代枚举所有因子
  • 只保存较大的因子,让较大的因子在后面需要的时候再分解成小因子

 

T2:E

两种情况。所有球里面的最大值$T_{max}$和最小值$T_{min}$要么是不同的颜色,要么在一起。

对于第一种情况式子是$(T_{max} - R_{min})*(B_{max} - T_{min})$

那么就把大的求放进左边,小的放进右边。

第二种情况是$(T_{max} - T_{min})*(R_{max} - R_{min})$

这时候左边就相当于垃圾桶,所有不要的值都往里面扔就是了。

目标就是在每一对球里选一个,使选出的球极差尽量小。

枚举$R_{min}$在考虑我们能否进行决策。

那就是如果一对球里小的那一个大于等于$R_{min}$那么就选小的,否则就选大的。

如果大的球也比$R_{min}$小那么这个就不合法了,更大的$R_{min}$也就不合法了。跳出。

这是O(n2)的。

但是如果我们从小到大枚举$R_{min}$的话,可以发现决策的变化就是把几个小球变成了大球。

那么每对球至多变化一次,单调指针扫的话总复杂度O(n)。

粘考场的O(n2)代码了。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<ctime>
 4 using namespace std;
 5 struct ps{
 6     int w,opt;
 7     friend bool operator<(ps a,ps b){
 8         return a.w<b.w||(a.w==b.w&&a.opt>b.opt);
 9     }
10 }p[200005];
11 int l[100005],r[100005],n,mxmx,mxmn=1e9,mnmx,mnmn=1e9;long long ans;
12 int main(){
13     scanf("%d",&n);
14     for(int i=1;i<=n;++i)scanf("%d%d",&l[i],&r[i]);
15     for(int i=1;i<=n;++i)if(l[i]>r[i])l[i]^=r[i]^=l[i]^=r[i];
16     for(int i=1;i<=n;++i)mxmx=max(mxmx,r[i]),mxmn=min(mxmn,r[i]),mnmx=max(mnmx,l[i]),mnmn=min(mnmn,l[i]);
17     ans=1ll*(mxmx-mxmn)*(mnmx-mnmn);
18     for(int i=1;i<=n;++i)p[i].w=l[i],p[n+i].w=r[i],p[i].opt=1;
19     sort(p+1,p+n+n+1);p[0].opt=1;
20     for(int j=1;p[j-1].opt&&clock()<1990000;++j){
21         int mnn=p[j].w,mxx=0;//printf("%d\n",mnn);
22         for(int i=1;i<=n;++i)if(l[i]>=mnn)mxx=max(mxx,l[i]);else mxx=max(mxx,r[i]);
23         ans=min(ans,1ll*(mxmx-mnmn)*(mxx-mnn));
24     }
25     printf("%lld\n",ans);
26 }
View Code

思路积累:

  • 贪心。
  • 单调指针:决策的连续性。
  • 分类讨论。

 

T3:F

首先要想到O(n2)的dp。

刚开始是想的三维,存第几轮时两个指针分别的位置。

然而其实完成一个指令后其中一个指针一定在目标处,记录另一个指针即可。

然后dp式子可以看出是区间加,单点修改,区间取min。

第一个式子直接区间加,第二个式子就是单点取min。

因为带绝对值所以拆开,左边的问f-j,右边的问f+j,两者取min后单点修改。

线段树。过程量爆int了。

记得读入。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cmath>
 4 using namespace std;
 5 #define int long long
 6 int w[800005][3],cl[800005],cr[800005],n,Q,q[100005],b,lz[800005];
 7 void build(int p,int l,int r){
 8     cl[p]=l;cr[p]=r;
 9     if(l==r){
10         if(l==b)w[p][0]=0,w[p][1]=-l,w[p][2]=l;
11         else w[p][0]=w[p][1]=w[p][2]=1e16;
12         return;
13     }
14     build(p<<1,l,l+r>>1);build(p<<1|1,(l+r>>1)+1,r);
15     for(int opt=0;opt<=2;++opt)w[p][opt]=min(w[p<<1][opt],w[p<<1|1][opt]);
16 }
17 void down(int p){
18     for(int opt=0;opt<=2;++opt)w[p<<1][opt]+=lz[p],w[p<<1|1][opt]+=lz[p];
19     lz[p<<1]+=lz[p];lz[p<<1|1]+=lz[p];
20     lz[p]=0;
21 }
22 void set(int p,int pos,int W){
23     if(cl[p]==cr[p]){
24         if(W<w[p][0])w[p][0]=W,w[p][1]=W-pos,w[p][2]=W+pos;
25         return;
26     }
27     if(lz[p])down(p);
28     if(pos<=cr[p<<1])set(p<<1,pos,W);
29     else set(p<<1|1,pos,W);
30     for(int opt=0;opt<=2;++opt)w[p][opt]=min(w[p<<1][opt],w[p<<1|1][opt]);
31 }
32 void add(int p,int l,int r,int W){
33     if(l<=cl[p]&&cr[p]<=r){
34         lz[p]+=W;
35         for(int opt=0;opt<=2;++opt)w[p][opt]+=W;
36         return;
37     }
38     if(lz[p])down(p);
39     if(l<=cr[p<<1])add(p<<1,l,r,W);
40     if(r>=cl[p<<1|1])add(p<<1|1,l,r,W);
41     for(int opt=0;opt<=2;++opt)w[p][opt]=min(w[p<<1][opt],w[p<<1|1][opt]);
42 }
43 int ask(int p,int l,int r,int opt){
44     if(l<=cl[p]&&cr[p]<=r)return w[p][opt];
45     if(lz[p])down(p);
46     return min(l<=cr[p<<1]?ask(p<<1,l,r,opt):1e16,r>=cl[p<<1|1]?ask(p<<1|1,l,r,opt):1e16);
47 }
48 main(){
49     scanf("%lld%lld%lld%lld",&n,&Q,&q[0],&b);
50     build(1,1,n);
51     for(int i=1;i<=Q;++i)scanf("%lld",&q[i]);
52     for(int i=1;i<=Q;++i){
53         int mn1=ask(1,1,q[i],1),mn2=ask(1,q[i],n,2);
54         add(1,1,n,abs(q[i]-q[i-1]));
55         set(1,q[i-1],min(mn1+q[i],mn2-q[i]));
56     }
57     printf("%lld\n",ask(1,1,n,0));
58 }
View Code

思路积累:

  • 线段树优化dp:把操作更新抽象为区间/单点操作,适用于第二维存值域(到现在靠自己一个都没做出来!!!)
  • 拆绝对值,左右分别讨论。

 

posted @ 2019-09-17 17:10  DeepinC  阅读(234)  评论(0编辑  收藏  举报