1. 程式人生 > 其它 >3.9省選模擬

3.9省選模擬

$3.9$省選模擬

今天的題原本沒打算寫題解的...怎奈我一下午都沒找到$solution,$為了造福後人(教練要求)就寫了

最近幾天感覺狀態不太對,很煩...

$T1$

首先這個題面就很生草...改一半粘一半,前後不通...

直接跑$dp$是很好想的,但是觀察資料範圍不是那回事,直接轉移不行,就考慮倍增優化轉移就好了

設三個陣列

$a[i][j][k]$表示從$j$出發耗費$2^i$血量,目的地是$k$的最遠道路

$b[i][j]$表示從$i$出發,耗費$p[i]$血量走到$j$的最遠距離

$c[i][j]$表示從$i$出發,花費$j$的金錢能走的最遠距離

$a[i][j][k]=max(a[i][j][k],a[i-1][j][h]+a[i-1][h][k])$

$b'[i][j]=b[i][j]+a[wei][k][j]$

這裡的$wei$表示對血量二進位制拆分

$c[j][i]=max(c[k][i-p[j]]+b[j][k])$

由於$c[x]$遞增,直接二分就好了

$T2$

#include<bits/stdc++.h>
#define int long long
//#define double long double
#define MAXN 1000005
#define ls (now<<1)
#define rs ((now<<1)|1)
using namespace std;
double x[MAXN],y[MAXN],pf[MAXN];
struct node { int l,r; double sumx,sumy,sumxx,sumxy; double Gai2S,Gai2T,lzx,lzy; bool Gai2; void Init() { sumx=sumy=sumxx=sumxy=0; } node operator + (const node &a) const { node Mid; Mid.Init(); Mid.sumx
=sumx+a.sumx; Mid.sumy=sumy+a.sumy; Mid.sumxx=sumxx+a.sumxx; Mid.sumxy=sumxy+a.sumxy; return Mid; } }tr[MAXN<<2]; int Sum(int l,int r) { return (l+r)*(r-l+1)/2; } void push_up(int now) { tr[now].sumx=(tr[ls].sumx+tr[rs].sumx); tr[now].sumy=(tr[ls].sumy+tr[rs].sumy); tr[now].sumxx=(tr[ls].sumxx+tr[rs].sumxx); tr[now].sumxy=(tr[ls].sumxy+tr[rs].sumxy); } void build(int now,int l,int r) { tr[now].l=l,tr[now].r=r; if(l==r) { tr[now].sumx=x[l]; tr[now].sumy=y[l]; tr[now].sumxx=x[l]*x[l]; tr[now].sumxy=x[l]*y[l]; return ; } int mid=(l+r)>>1; build(ls,l,mid); build(rs,mid+1,r); push_up(now); } int Len(int now) { return tr[now].r-tr[now].l+1; } void pd(int now) { if(tr[now].Gai2) { int Gai2S=tr[now].Gai2S; int Gai2T=tr[now].Gai2T; // cout<<"Gai: "<<Gai2S<<" "<<Gai2T<<endl; tr[ls].lzx=0,tr[ls].lzy=0; tr[ls].Gai2=1; tr[ls].Gai2S=Gai2S; tr[ls].Gai2T=Gai2T; tr[ls].sumx=Sum(tr[ls].l,tr[ls].r)+Gai2S*Len(ls); tr[ls].sumy=Sum(tr[ls].l,tr[ls].r)+Gai2T*Len(ls); // cout<<""<<tr[ls].sumx<<" "<<tr[ls].sumy<<endl; tr[ls].sumxy=(pf[tr[ls].r]-pf[tr[ls].l-1])+Gai2S*Gai2T*Len(ls)+(Gai2S+Gai2T)*Sum(tr[ls].l,tr[ls].r); tr[ls].sumxx=(pf[tr[ls].r]-pf[tr[ls].l-1])+2*Sum(tr[ls].l,tr[ls].r)*Gai2S+Gai2S*Gai2S*Len(ls); tr[rs].lzx=0,tr[rs].lzy=0; tr[rs].Gai2=1; tr[rs].Gai2S=Gai2S; tr[rs].Gai2T=Gai2T; tr[rs].sumx=Sum(tr[rs].l,tr[rs].r)+Gai2S*Len(rs); tr[rs].sumy=Sum(tr[rs].l,tr[rs].r)+Gai2T*Len(rs); tr[rs].sumxy=(pf[tr[rs].r]-pf[tr[rs].l-1])+Gai2S*Gai2T*Len(rs)+(Gai2S+Gai2T)*Sum(tr[rs].l,tr[rs].r); tr[rs].sumxx=(pf[tr[rs].r]-pf[tr[rs].l-1])+2*Sum(tr[rs].l,tr[rs].r)*Gai2S+Gai2S*Gai2S*Len(rs); tr[now].Gai2=0; tr[now].Gai2S=0; tr[now].Gai2T=0; } else if(tr[now].lzx||tr[now].lzy) { int lzx=tr[now].lzx; int lzy=tr[now].lzy; tr[ls].lzx+=lzx; tr[ls].lzy+=lzy; tr[ls].sumxy+=(tr[ls].sumy*lzx+tr[ls].sumx*lzy+lzx*lzy*Len(ls)); tr[ls].sumxx+=(2*lzx*tr[ls].sumx+lzx*lzx*Len(ls)); tr[ls].sumx+=(lzx*Len(ls)); tr[ls].sumy+=(lzy*Len(ls)); tr[rs].lzx+=lzx; tr[rs].lzy+=lzy; tr[rs].sumxy+=(tr[rs].sumy*lzx+tr[rs].sumx*lzy+lzx*lzy*Len(rs)); tr[rs].sumxx+=(2*lzx*tr[rs].sumx+lzx*lzx*Len(rs)); tr[rs].sumx+=(lzx*Len(rs)); tr[rs].sumy+=(lzy*Len(rs)); tr[now].lzx=0; tr[now].lzy=0; } } node query(int now,int l,int r) { pd(ls);pd(rs); if(tr[now].l>=l&&tr[now].r<=r) { // cout<<"now: "<<tr[now].l<<" " return tr[now]; } pd(now); int mid=(tr[now].l+tr[now].r)>>1; node res; res.Init(); if(l<=mid) res=(res+query(ls,l,r)); if(r>mid) res=(res+query(rs,l,r)); return res; } void change1(int now,int l,int r,double x1,double y1) { pd(ls);pd(rs); if(tr[now].l>=l&&tr[now].r<=r) { tr[now].sumxy+=(x1*tr[now].sumy+y1*tr[now].sumx+x1*y1*Len(now)); tr[now].sumxx+=(2*x1*tr[now].sumx+x1*x1*Len(now)); tr[now].sumx+=(x1*Len(now)); tr[now].sumy+=(y1*Len(now)); tr[now].lzx+=x1; tr[now].lzy+=y1; pd(ls),pd(rs); return ; } pd(now); int mid=(tr[now].l+tr[now].r)>>1; if(l<=mid) change1(ls,l,r,x1,y1); if(r>mid) change1(rs,l,r,x1,y1); push_up(now); } void change2(int now,int l,int r,double x1,double y1) { pd(ls);pd(rs); if(tr[now].l>=l&&tr[now].r<=r) { tr[now].lzx=0;tr[now].lzy=0; tr[now].Gai2=1,tr[now].Gai2S=x1,tr[now].Gai2T=y1; tr[now].sumx=Sum(tr[now].l,tr[now].r)+x1*Len(now); tr[now].sumy=Sum(tr[now].l,tr[now].r)+y1*Len(now); tr[now].sumxy=(pf[tr[now].r]-pf[tr[now].l-1]+x1*y1*Len(now)+(x1+y1)*Sum(tr[now].l,tr[now].r)); tr[now].sumxx=(pf[tr[now].r]-pf[tr[now].l-1]+2*Sum(tr[now].l,tr[now].r)*x1+x1*x1*Len(now)); pd(ls);pd(rs); return ; } pd(now); int mid=(tr[now].l+tr[now].r)>>1; if(l<=mid) change2(ls,l,r,x1,y1); if(r>mid) change2(rs,l,r,x1,y1); push_up(now); } void DE(int now) { cout<<"now: "<<now<<" "<<tr[now].sumx<<" "<<tr[now].sumy<<" "<<tr[now].sumxx<<" "<<tr[now].sumxy<<" "<<tr[now].lzx<<" "<<tr[now].lzy<<" "<<tr[now].Gai2<<endl; if(tr[now].l==tr[now].r) return ; DE(ls);DE(rs); } int n,q; signed main() { // freopen("gold.in","r",stdin); // freopen("gold.out","w",stdout); cin>>n>>q; for(int i=1;i<=n;i++) { scanf("%lf",&x[i]); } for(int i=1;i<=n;i++) { scanf("%lf",&y[i]); } build(1,1,n); // DE(1); for(int i=1;i<=1000000;i++) { pf[i]=pf[i-1]+pow(i*1.0,2); } int opt,l,r; double S,T; for(int i=1;i<=q;i++) { scanf("%lld",&opt); if(opt==1) { scanf("%lld%lld",&l,&r); pd(1); node Fin=query(1,l,r); int len=(r-l+1); double xb=(Fin.sumx/(len*1.0)),yb=(Fin.sumy/(len*1.0)); double Ans; Ans=(Fin.sumxy-xb*Fin.sumy+xb*yb*len-Fin.sumx*yb)/(Fin.sumxx+xb*xb*len-2*Fin.sumx*xb); // cout<<"que: "<<Fin.sumx<<" "<<Fin.sumy<<" "<<Fin.sumxx<<" "<<Fin.sumxy<<endl; printf("%.6f\n",Ans); } if(opt==2) { scanf("%lld%lld%lf%lf",&l,&r,&S,&T); pd(1); change1(1,l,r,S,T); pd(1); } if(opt==3) { scanf("%lld%lld%lf%lf",&l,&r,&S,&T); pd(1); change2(1,l,r,S,T); pd(1); } // DE(1); } }

 

程式碼巨長...就一線段樹裸題

 

寫不是最痛苦的,$bug$在哪都可能出現,不過寫著時候挺舒服的,式子很好推

$T3$

 

 

神仙題,我一直在 $while(1)$ 猜結論+驗證+錯

二分答案很好想(我菜沒想到),然後轉化為判定

判定的話需要一個轉化,一共$n$個石頭看成$n$個二進位制串,只要每個都不同就好了,而且每一位不能超過$m$個$1$

那麼貪心去判定,每次減少$C(mid,i)$,然後$m$減少$C(mid-1,i-1)$

為什麼減少$C(mid-1,i-1),$考慮每一位被多少個佔了,我們總共選$C(mid,i)$個

那麼每一個被選中的次數是$C(mid-1,i-1)$

那麼最後一個就特殊判斷一下$m\times mid>n\times i$就好了