[考试反思]0512省选模拟94:畏惧

最近好多构造啊(还不是课件里那么难的那种)。。。产生了一种我排名虚高的局面

这套题对我很好。。。一个暴力一个构造一个暴力。

$T1$的正解是神奇的计算几何。幸亏没想到,不然真不知道要浪费多少时间。。。

赛后调一个裸的凸包模板调了好几个小时(并不怎么理解)。。。

心烦。。。$LCT$和计算几何真是俩很难迈过去的坎

 

T1:a(终)

大意:$n$点有权值$A_i,B_i$。构造一条回路(不需要经过所有点),满足$B$最小的点到$B$最大的点路径上$B$非严格递增,最大到最小非严格递减。

走一步$i \to j$的贡献是$\frac{(A_i-A_j)B_iB_j}{A_iA_j}$。最大化代价。$n \le 10^5,0 <|A| \le 100$

贡献的式子可以简单化为$(A_i \frac{A_j}{B_j})-(A_j \frac{A_i}{B_i})$

$(A,\frac{A}{B})$。向量叉积形式。发现求的就是面积。维护凸包即可。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define S 100005
 4 int a[S],b[S],n,t; long double ans;
 5 struct P{
 6     long double x,y;
 7     friend bool operator<(P a,P b){return fabs(a.x-b.x)>1e-7?a.x<b.x:a.y<b.y;}
 8     long double operator^(P b){return x*b.y-y*b.x;}
 9     P operator-(P b){return (P){x-b.x,y-b.y};}
10 }p[S],q[S];
11 int main(){
12     scanf("%d",&n);
13     for(int i=1;i<=n;++i)scanf("%d",&a[i]),b[i]=b[i-1]+a[i],p[i]=(P){b[i],1.*b[i]/a[i]};
14     sort(p+1,p+1+n);
15     for(int i=1;i<=n;++i){
16         while(t>1&&(q[t]-q[t-1]^p[i]-q[t])<1e-7)t--;
17         q[++t]=p[i];
18     }
19     int lim=t;
20     for(int i=n-1;i;--i){
21         while(t>lim&&(q[t]-q[t-1]^p[i]-q[t])<1e-7)t--;
22         q[++t]=p[i];
23     }
24     for(int i=1;i<=t;++i)ans+=q[i]^q[i%t+1];
25     printf("%.5Lf\n",ans/2);
26 }
View Code

 

T2:b(壕)

大意:数列,$a_i \in [0,6]$。每次操作可以选择一个区间整体加一个数后对$7$取模。最小化全变成$0$的步数。$n \le 500$

区间加差分转化为一点加一点减。(为了方便原序列末尾需要加一个$0$)。这样的话一次操作后序列元素的和不会变。

对于一个大小为$k$的集合。我们把第一个数加成$0$并等量减第二个数,后续同理,则把$k-1$个数弄成$0$时最后一个数一定也是$0$

所以说对于和为$0$的大小为$x$的集合需要$x-1$次操作。所以总操作次数就是$n+1-cnt$。$cnt$是划分的集合数。故要最大化权值和为$0$的集合。

元素$0$肯定单独成一个集合了。下面证明如果$x$和$7-x$同时存在那么它们配对一定最优:

如果存在一种方案使得$x\in A,7-x \in B$。要求$A,B$均不可再分裂成两个权值和为$0$的子集。

对于这种情况我们把$x,7-x$单独拿出来做一个集合。$A,B$的剩余部分构成另一个集合,这样的话集合数没有变。

但是新集合可能能分裂成两个小的权值和为$0$的集合使总集合数变多。所以说$x,7-x$配对答案可能更优而不会变差。

所以$x,7-x$两两配对之后较少的一种就用完了。$(1,6),(2,5),(3,4)$每对只剩下一个。

也就是只剩下最多$3$种元素参加配对。这样直接做一个$O(n^3)$的$dp$就行了。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int dp[502][502][502],a[501],n,b[8],ans,A,B,C,u[7][7];
 4 int mo(int x){x=x%7+7;return x>=7?x-7:x;}
 5 int main(){
 6     scanf("%d",&n);
 7     for(int i=1;i<=n;++i)scanf("%d",&a[i]),b[mo(a[i]-a[i-1])]++;
 8     b[mo(-a[n])]++; n++;
 9     b[7]=b[0]; for(int i=0,x;i<4;++i)x=min(b[i],b[7-i]),ans+=x,b[i]-=x,b[7-i]-=x;
10     for(int i=1;i<8;++i)if(b[i])(A?(B?C:B):A)=i;
11     for(int i=0;i<7;++i)for(int j=0;j<7;++j){
12         int x=mo(i*A+j*B);
13         while(u[i][j]<=b[C]&&x)++u[i][j],x=mo(x+C);
14     }u[0][0]=7;
15     for(int i=b[A];i>=0;i-=7)for(int j=b[B];j>=0;j-=7)for(int k=b[C];k>=0;k-=7)
16         dp[i][j][k]=(b[A]-i+b[B]-j+b[C]-k)/7;
17     for(int i=b[A];~i;--i)for(int j=b[B];~j;--j)for(int k=b[C];~k;--k)
18         for(int x=0;x<7&&x<=i;++x)for(int y=0;y<7&&y<=j;++y)if(k>=u[x][y])
19             dp[i-x][j-y][k-u[x][y]]=max(dp[i-x][j-y][k-u[x][y]],dp[i][j][k]+1);
20     printf("%d\n",n-(ans+dp[0][0][0]));
21 }
View Code

 

T3:c(息)

大意:给定$F_{0,i}$,$F_{x,i}=F_{x-1,i}+F_{x,i-1}$。支持修改$F_{0,i}$或查询$F_{x,i}$。$i \le 10^5,x \le 20,m \le 10^5$

一种暴力做法是每次修改的时候重置整个$F$表。修改$O(20n)$查询$O(1)$

一种暴力做法是用组合数统计每个修改对某一个询问的贡献。修改$O(1)$查询$O(m)$

均摊一下。每$\sqrt{20n}$定期重置$F$表并清空修改栈。$O(n\sqrt{n})$

 1 #include<cstdio>
 2 const int mod=1000000007,S=100055; const long long mxv=8000000000000000000;
 3 int F[21][S],n,m,c[S],C[S][21];
 4 struct my_set{
 5     bool al[S];int v[S],cnt;
 6     void ins(int x){if(!al[x])al[x]=1,v[++cnt]=x;}
 7     void clear(){while(cnt)al[v[cnt--]]=0;}
 8 }M;
 9 int mo(int a){return a>=mod?a-mod:a;}
10 void Mo(long long&x){if(x>=mxv||x<=-mxv)x%=mod;}
11 void rebuild(){
12     for(int i=1;i<=n;++i)F[0][i]=c[i];
13     for(int t=1;t<=20;++t)for(int i=1;i<=n;++i)F[t][i]=mo(F[t-1][i]+F[t][i-1]);
14     M.clear();
15 }
16 int main(){
17     scanf("%d%d",&n,&m);
18     for(int i=C[0][0]=1;i<=n+20;++i)for(int j=C[i][0]=1;j<=20;++j)C[i][j]=mo(C[i-1][j]+C[i-1][j-1]);
19     for(int i=1;i<=n;++i)scanf("%d",&c[i]);
20     rebuild();
21     for(int i=1,o,x,y;i<=m;++i){
22         scanf("%d%d%d",&o,&x,&y);
23         if(o==1)c[x]=y,M.ins(x);
24         else{
25             if(x==0){printf("%d\n",c[y]);continue;}
26             if(M.cnt>1414)rebuild();
27             long long ans=F[x][y];
28             for(int i=1;i<=M.cnt;++i)if(M.v[i]<=y)ans+=(0ll+c[M.v[i]]-F[0][M.v[i]])*C[y-M.v[i]+x-1][x-1],Mo(ans);
29             printf("%d\n",mo(ans%mod+mod));
30         }
31     }
32 }
View Code

 

posted @ 2020-05-12 21:54  DeepinC  阅读(263)  评论(0编辑  收藏  举报