CSP-S模拟4 石子游戏 大鱼吃小鱼 黑客 黑客-续

T2:线段树二分【序列问题】
https://tg.hszxoj.com/contest/527/problem/2
一个显然的贪心是每次吃当前能吃的体积最大的鱼。
考虑直接模拟这个过程,可能会吃N次鱼。我们考虑当前不能吃的体积最小
的鱼,显然只有我们的体积超过了这条鱼,我们的可选集合才会有变化,如果这
条鱼的体积大于等于我们的目标,那我们只需要计算现有的集合需要吃几条能达
到目标即可。于是,我们每一步需要做的就是对于确定的数字集合,求出使得和
达到某个值的最少步数即可,由于可选的数字是连续的,在线段树上二分即可。
接下来我们来分析数字范围变化的次数。考虑我们当前和为A,不能选的最
小体积是B(显然B>A),我们在选出一些数字之后,得到A+x>B,接着我们得到
了选不到的最小体积C,我们再次二分会得到A+x+y>C,注意到,y≥B,也就是
说,A+x+y≥A+x+B>A+B>A+A,于是,我们在两次二分之后,手里的和至少翻
倍,所以我们只需要log次就一定能得到答案

对于线段树在每次询问删除后的恢复,只需要另外开一个数组记录本次删除都涉及了那些节点,最后再恢复就行。因为只涉及我操作的时候的节点,所以复杂度是对的
O(m*log^2n)

点击查看代码




#include<bits/stdc++.h>
#define int long long
#define N 400000+100
using namespace std;
int n,q,w[N],san[N<<2],tot,ans,zhi,now,ne,tong1[N<<2];
bool bo=1,vis[N<<2],vvv=1;
struct jj
{int opt,s,k,w;}Q[N];
multiset<int>st;
struct tt{int sum,siz,tag;}tmp[N<<3];
struct zxb
{int sum[N<<2],siz[N<<2],tag[N<<2];
inline void pushup(int x)
{   if(!vis[x] and vvv)
{tong1[++zhi]=x,tmp[zhi]=(tt)
{sum[x],siz[x],tag[x]},vis[x]=1;}
    sum[x]=sum[x<<1]+sum[x<<1|1];
    siz[x]=siz[x<<1]+siz[x<<1|1];
    return;
}
inline void pushdown(int x)
{
if(!vis[x<<1])
{tong1[++zhi]=x<<1,
tmp[zhi]=(tt){sum[x<<1],siz[x<<1],tag[x<<1]},vis[x<<1]=1;}
if(!vis[x<<1|1])
{tong1[++zhi]=x<<1|1,
tmp[zhi]=(tt){sum[x<<1|1],
siz[x<<1|1],tag[x<<1|1]},vis[x<<1|1]=1;}
sum[x<<1]=sum[x<<1|1]=siz[x<<1]=siz[x<<1|1]=0;
tag[x<<1]=tag[x<<1|1]=1;tag[x]=0;
}
inline void ins(int x,int l,int r,int pos,int val)
{   if(l==r)
    {   siz[x]+=val;
        sum[x]+=san[l]*val;
        return;
    }
    int mid=(l+r)>>1;
    if(mid<pos)ins(x<<1|1,mid+1,r,pos,val);
    else ins(x<<1,l,mid,pos,val);
    pushup(x);
}
inline int query(int x,int l,int r,int L,int R)
{   if(L>R)return 0;
    if(l>=L and r<=R)return sum[x];
    int mid=(l+r)>>1,res=0;
    if(tag[x])pushdown(x);
    if(mid<R and sum[x<<1|1])res+=query(x<<1|1,mid+1,r,L,R);
    if(mid>=L and sum[x<<1])res+=query(x<<1,l,mid,L,R);
    return res;
}
inline void calc(int x,int l,int r,int L,int R)
{   if(l==r and sum[x]>=ne)
    {   if(!vis[x])
        {tong1[++zhi]=x,tmp[zhi]=(tt){sum[x],siz[x],tag[x]},vis[x]=1;}
        siz[x]-=(ne/san[l])+(ne%san[l]!=0);
        
        ans+=(ne/san[l])+(ne%san[l]!=0);
        now+=((ne/san[l])+(ne%san[l]!=0))*san[l];
        ne-=((ne/san[l])+(ne%san[l]!=0))*san[l];
        bo=0;
        sum[x]=siz[x]*san[l];
        return;
    }
    if(r<=R)
    {   if(sum[x]<=ne)
        {   ne-=sum[x];now+=sum[x];
            if(ne<=0)bo=0;ans+=siz[x];
            if(!vis[x])
            {tong1[++zhi]=x,tmp[zhi]=(tt){sum[x],siz[x],tag[x]},vis[x]=1;}
            sum[x]=0;siz[x]=0;tag[x]=1;
            return;
        }
    }
    int mid=(l+r)>>1;
    if(tag[x])pushdown(x);
    if(mid>=R){(void)calc(x<<1,l,mid,L,R);pushup(x);return ;}
    if(bo and sum[x<<1|1])calc(x<<1|1,mid+1,r,L,R);
    if(bo and sum[x<<1])calc(x<<1,l,mid,L,R);
    pushup(x);
}
}tree;
inline void work(int s,int k)
{  
    int need=k-s,val;now=s;ans=0;zhi=0;
    while(now<k)
    {   auto it=st.lower_bound(now);
        if(it==st.end())val=999999999999999999;
        else val=*it; 
        ne=min(k-now,val-now+1);int lst=ne;
        int pos=lower_bound(san+1,san+1+tot,now)-san;bo=1;
        --pos;
        if(pos)tree.calc(1,1,tot,1,pos);
        else break;
        if(bo)break;if(it==st.end())break;
        need-=(lst-ne);
    }
    if(ne>0)puts("-1");
    else printf("%lld\n",ans);
    for(int i=1;i<=zhi;++i)
    {   int x=tong1[i];
        vis[x]=0;
        tree.sum[x]=tmp[i].sum;
        tree.siz[x]=tmp[i].siz;
        tree.tag[x]=0;
    }
}
signed main()
{   freopen("fish.in","r",stdin);
    freopen("fish.out","w",stdout);
    scanf("%lld",&n);
    for(int i=1;i<=n;++i)scanf("%lld",&w[i]),san[++tot]=w[i],st.insert(w[i]);
    scanf("%lld",&q);
    for(int i=1;i<=q;++i)
    {   scanf("%lld",&Q[i].opt);
        if(Q[i].opt==1)scanf("%lld%lld",&Q[i].s,&Q[i].k);
        if(Q[i].opt==2)scanf("%lld",&Q[i].w),san[++tot]=Q[i].w;
        if(Q[i].opt==3)scanf("%lld",&Q[i].w),san[++tot]=Q[i].w;
    }
    sort(san+1,san+1+tot);
    tot=unique(san+1,san+1+tot)-san-1;
    san[++tot]=999999999999999999;
    for(int i=1;i<=n;++i)
    {   int pos=lower_bound(san+1,san+1+tot,w[i])-san;
        vvv=0;
        tree.ins(1,1,tot,pos,1);
    }
    vvv=1;
    for(int i=1;i<=q;++i)
    {   if(Q[i].opt==1)
        {   if(Q[i].s>=Q[i].k){puts("0");continue;}
            work(Q[i].s,Q[i].k);
        }
        if(Q[i].opt==2)
        {   vvv=0;
            int pos=lower_bound(san+1,san+1+tot,Q[i].w)-san;
            tree.ins(1,1,tot,pos,1);st.insert(Q[i].w);
            vvv=1;
        }
        if(Q[i].opt==3)
        {   vvv=0;
            int pos=lower_bound(san+1,san+1+tot,Q[i].w)-san;
            tree.ins(1,1,tot,pos,-1);st.erase(st.find(Q[i].w));
            vvv=1;
        }
    }
}

T3:

给你A,B,C,D求x=[A,B],y=[C,D]范围内的数[x/y]最简形式(x'+y')<=999的数的[x'+y']的总计和值.(a,b,c,d<=1e14)

发现合法的(a/b)形式的数很少,所以枚举化简之后是(a/b)形式的数在[A,B][C,D]之间的有多少对,取交集就行。

【易错】freopen("a.in","r",stdin),字字珠玑,不能在文件名后面多空格!!! 比如这样 freopen("a.in ","r",stdin)
,不然你就完了......

点击查看代码






#include<bits/stdc++.h>
using namespace std;
#define _f(i,a,b) for(register int i=a;i<=b;++i)
#define f_(i,a,b) for(register int i=a;i>=b;--i)
#define chu printf
#define ll long long
#define ull unsigned long long
inline ll re()
{
    ll x=0,h=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')h=-1;
        ch=getchar();
    }
    while(ch<='9'&&ch>='0')
    {
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*h;
}
const int N=5e5+100;
const ll mod=1e9+7;
ll a,b,c,d;
inline ll gcd(ll x,ll y)
{
    if(!y)return x;
    return gcd(y,x%y);
}
int main()
{
  freopen("hacker.in","r",stdin);
  freopen("hacker.out","w",stdout);
   a=re(),b=re(),c=re(),d=re();ll sum=0;
	for(ll i=1;i<=999;++i)
	for(ll j=1;j<=999-i;++j)
	{
		if(gcd(i,j)!=1)continue;
	//	chu("i:%lld j:%lld\n",i,j);
		ll lb=ceill((double)a/i),rb=b/i;
		ll lb2=ceill((double)c/j);
		ll rb2=d/j;
		lb=max(lb,lb2);
		rb=min(rb,rb2);
		if(rb<lb)continue;
	//	if(i==5&&j==3)chu("%d--%d\n",lb,rb);
		sum+=(ll)(i+j)*(rb-lb+1);
		sum%=mod;
	}
   chu("%lld",sum);
    return 0;
}
/*

*/
posted on 2022-09-12 18:33  HZOI-曹蓉  阅读(154)  评论(0编辑  收藏  举报