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$就好了

 

 

 

感觉这个越看越上头...

posted @ 2022-03-09 19:08  Authentic_k  阅读(32)  评论(3编辑  收藏  举报