【JZOJ 5439】【NOIP2017提高A组集训10.31】Calculate

本文介绍了一种通过将数据分组来优化计算效率的方法。该方法适用于特定类型的数学问题求解,通过对输入数据进行合理划分并利用预处理技巧减少计算量,从而实现高效的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

这里写图片描述

这里写图片描述

Solution

发现a的访问很小,考虑从这入手,
把所有的数按a分成1000组,
对于每一组(设a全为x),首先,T每增加x,组里的每个数一定都会贡献+1,
但显然,有可能不用增加x那么多,有些数就已经有贡献了,如:a=5,b=1,当T=1的时候,它的贡献就从-1变成0 了,
发现这些数均是bmodbTmodb
那么这个用暴力维护即可,

复杂度:O(10002log(109)+1000m)

Code

#include <cstdio>
#include <algorithm>
#include <cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
#define min(q,w) ((q)>(w)?(w):(q))
#define max(q,w) ((q)<(w)?(w):(q))
#define NX(q) ((q)&(-(q)))
using namespace std;
typedef long long LL;
const int N=100500,M=1000;
int read(int &n)
{
    char ch=' ';int q=0,w=1;
    for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
    if(ch=='-')w=-1,ch=getchar();
    for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int m,n,ans,mx;
int a[N],b[N],bv[N];
int f[M+5][M+5];
LL LW;
void change(int e,int q,int l2)
{
    if(!q)return;
    // for(;q<=e;q+=NX(q))f[e][q]+=l2;
    fo(i,q,e)f[e][i]+=l2;
}
int find(int e,int q)
{
    // int ans=0;for(;q>0;q-=NX(q))ans+=f[e][q];return ans;
    return f[e][q];
}
LL JS(int T)
{
    LL ans=0;
    fo(i,1,mx)if(bv[i])
    {
        ans+=(LL)bv[i]*(LL)((T)/i);
        ans+=(LL)find(i,T%i);
    }
    return ans;
}
int main()
{
    freopen("calculate.in","r",stdin);
    freopen("calculate.out","w",stdout);
    int q,w,e,_;
    for(read(_);_--;)
    {
        memset(f,0,sizeof(f));
        fo(i,0,M)bv[i]=0;
        LW=mx=0;
        read(n),read(m);
        fo(i,1,n)read(a[i]);
        fo(i,1,n)
        {
            read(b[i]);mx=max(mx,a[i]);
            change(a[i],b[i]%a[i],1);
            bv[a[i]]++;
            LW-=(LL)b[i]/a[i];
            if(b[i]%a[i])LW--;
        }
        fo(i,1,m)
        {
            read(e),read(q);
            if(e<3)
            {
                LW+=(LL)b[q]/a[q];bv[a[q]]--;
                if(b[q]%a[q])LW++;
                change(a[q],b[q]%a[q],-1);
                if(e==1)read(a[q]);else read(b[q]);
                mx=max(mx,a[q]);
                LW-=(LL)b[q]/a[q];bv[a[q]]++;
                if(b[q]%a[q])LW--;
                change(a[q],b[q]%a[q],1);
            }
            else if(e==3)
            {
                int l=1,r=2e9;
                while(l<r)
                {
                    int mid=((LL)l+r)>>1;
                    if(LW+JS(mid)>=q)r=mid;
                    else l=mid+1;
                }
                printf("%d\n",l);
            }
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值