[考試反思]0511省選模擬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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章