[2017纪中10-31]Calculate 数论

题面
考虑二分答案T。问题转化成如何高效计算S(T)。
化式子:
[2017纪中10-31]Calculate 数论_第1张图片
分开来除,加上他们的余数和的贡献。
发现Ai最大1000,考虑把(Ai,Bi)按照Ai分类,每一类维护cnt,sum,rst[0~Ai-1],分别表示数对的个数,(-Bi)/Ai的和,(-Bi)%Ai取值的前缀和,那么对于每一个Ai都可以O(1)计算,对于每个查询O(1000*log10^12)。
修改直接暴力修改即可,对于每个修改O(1000)。
代码:

#include
#include
#include
#define ll long long
using namespace std;
const int maxn=100010;
int n,m,a[maxn],b[maxn];
ll sum[1010],cnt[1010],rst[1010][1010];
int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar(); }
    while(ch>='0'&&ch<='9') {x=x*10+ch-'0'; ch=getchar(); }
    return x*f;
}
inline ll div(ll a,int b)
{
    ll t=a/b;
    if(a>=0||b*t==a) return t;
    return t-1;
}
inline ll mod(ll a,int b)
{
    ll t=a%b;
    if(t>=0) return t;
    else return t+b;
}
ll cal(ll x)
{
    ll re=0;
    for(int i=1;i<=1000;i++)
        if(cnt[i]>0)
        {
            ll t=div(x,i);
            re+=sum[i]+t*cnt[i]+rst[i][i-1]-rst[i][i-(x-t*i)-1];
        }       
    return re;  
}
int main()
{
    int ca=read();
    while(ca--)
    {
        n=read();m=read();
        for(int i=1;i<=n;i++)
            a[i]=read();
        for(int i=1;i<=n;i++)
            b[i]=-read();
        memset(cnt,0,sizeof(cnt));
        memset(sum,0,sizeof(sum));
        memset(rst,0,sizeof(rst));
        for(int i=1;i<=n;i++)
        {
            cnt[a[i]]++;
            sum[a[i]]+=div(b[i],a[i]);
            rst[a[i]][mod(b[i],a[i])]++;
        }
        for(int i=1;i<=1000;i++)
            for(int j=1;j1];
        while(m--)
        {
            int opt=read(),x=read();
            if(opt==1) 
            {
                sum[a[x]]-=div(b[x],a[x]);cnt[a[x]]--;
                for(int i=mod(b[x],a[x]);isum[a[x]]+=div(b[x],a[x]);cnt[a[x]]++;
                for(int i=mod(b[x],a[x]);iif(opt==2) 
            {
                sum[a[x]]-=div(b[x],a[x]);
                for(int i=mod(b[x],a[x]);isum[a[x]]+=div(b[x],a[x]);
                for(int i=mod(b[x],a[x]);iif(opt==3)
            {
                ll l,r;
                if(n>=990) l=-1e9,r=1e9;
                else l=-2e12,r=2e12;
                while(l>1;
                    if(cal(mid)>=x) r=mid;
                    else l=mid+1;
                }
                printf("%lld\n",l);
            }
        }
    }
    return 0;
}

你可能感兴趣的:(数论)