A

分类讨论直接前缀和搞搞。

/*
Author: CNYALI_LK
LANG: C++
PROG: a.cpp
Mail: cnyalilk@vip.qq.com
*/
#include<bits/stdc++.h>
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define DEBUG printf("Passing [%s] in LINE %lld\n",__FUNCTION__,__LINE__)
#define Debug debug("Passing [%s] in LINE %lld\n",__FUNCTION__,__LINE__)
#define all(x) x.begin(),x.end()
#define x first
#define y second
using namespace std;
const double eps=1e-8;
const double pi=acos(-1.0);
typedef long long ll;
typedef pair<ll,ll> pii;
template<class T>ll chkmin(T &a,T b){return a>b?a=b,1:0;}
template<class T>ll chkmax(T &a,T b){return a<b?a=b,1:0;}
template<class T>T sqr(T a){return a*a;}
template<class T>T mmin(T a,T b){return a<b?a:b;}
template<class T>T mmax(T a,T b){return a>b?a:b;}
template<class T>T aabs(T a){return a<0?-a:a;}
#define min mmin
#define max mmax
#define abs aabs
ll read(){
    ll s=0,base=1;
    char c;
    while(!isdigit(c=getchar()))if(c=='-')base=-base;
    while(isdigit(c)){s=s*10+(c^48);c=getchar();}
    return s*base;
}
const ll p=19260817;
ll dis[204847],fdis[204847],tdis[204847];
ll w[204847],fw[204847],tw[204847],qw[204847];
int main(){
#ifdef cnyali_lk
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
#endif
    ll n,m,x,l,r;
    n=read();
    m=read();
    for(ll i=1;i<n;++i)dis[i]=read()%p;
    for(ll i=1;i<=n;++i){
        w[i]=read()%p;
        qw[i]=(qw[i-1]+w[i])%p;
    }
    for(ll i=2;i<=n;++i){
        fdis[i]=(dis[i-1]+fdis[i-1])%p;
        fw[i]=(fw[i-1]+fdis[i]*w[i])%p;
    }
    for(ll i=n-1;i;--i){
        tdis[i]=(tdis[i+1]+dis[i])%p;
        tw[i]=(tw[i+1]+tdis[i]*w[i])%p;
    }
    for(;m;--m){
        x=read();l=read();r=read(); 
        if(x<l){
            printf("%lld\n",(fw[r]-fw[l-1]+p-fdis[x]*(qw[r]-qw[l-1]+p)%p+p)%p);
        }
        else if(r<x){
            printf("%lld\n",(tw[l]-tw[r+1]+p-tdis[x]*(qw[r]-qw[l-1]+p)%p+p)%p);
        }
        else{
            printf("%lld\n",((fw[r]-fw[x]+p-fdis[x]*(qw[r]-qw[x])%p+p)+(tw[l]-tw[x]+p-tdis[x]*(qw[x-1]-qw[l-1])%p+p))%p);
        }
    }
    return 0;
}

B

首先显然两部分的区域在各行格列是连续的。 类似于这样:

pic

然后每一行的轮廓线是单调的。

设最大值为Mx,最小值为Mn。

对于答案k,满足一部分$\ge Mx-k$(假设为红色),另一部分$\le Mn+k$(假设为蓝色)。

红色可能在左上右上左下右下。

那么就可以通过将这个矩阵旋转90°多次(0,1,2,3次),来使得红色在左上。

二分答案k,贪心的计算红色,判断蓝色是否满足$\le Mn+k$。

时间复杂度$O(nm\log A)$ A是元素大小。

/*
Author: CNYALI_LK
LANG: C++
PROG: b.cpp
Mail: cnyalilk@vip.qq.com
*/
#include<bits/stdc++.h>
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define DEBUG printf("Passing [%s] in LINE %lld\n",__FUNCTION__,__LINE__)
#define Debug debug("Passing [%s] in LINE %lld\n",__FUNCTION__,__LINE__)
#define all(x) x.begin(),x.end()
#define x first
#define y second
using namespace std;
const double eps=1e-8;
const double pi=acos(-1.0);
typedef long long ll;
typedef pair<ll,ll> pii;
template<class T>ll chkmin(T &a,T b){return a>b?a=b,1:0;}
template<class T>ll chkmax(T &a,T b){return a<b?a=b,1:0;}
template<class T>T sqr(T a){return a*a;}
template<class T>T mmin(T a,T b){return a<b?a:b;}
template<class T>T mmax(T a,T b){return a>b?a:b;}
template<class T>T aabs(T a){return a<0?-a:a;}
#define min mmin
#define max mmax
#define abs aabs
ll read(){
    ll s=0,base=1;
    char c;
    while(!isdigit(c=getchar()))if(c=='-')base=-base;
    while(isdigit(c)){s=s*10+(c^48);c=getchar();}
    return s*base;
}
ll a[2047][2047],rj[2047],b[2047][2047];
ll n,m,xmin,xmax;
ll check(ll w){
    rj[0]=m;
    for(ll i=1;i<=n;++i){
        for(rj[i]=0;rj[i]<rj[i-1]&&a[i][rj[i]+1]<=xmin+w;++rj[i]);
        for(ll j=rj[i]+1;j<=m;++j)if(a[i][j]<xmax-w)return 0;
    }
    return 1;
}
void rrotate(){
    for(ll i=1;i<=n;++i)for(ll j=1;j<=m;++j)b[j][n-i+1]=a[i][j];
    swap(n,m);
    for(ll i=1;i<=n;++i)for(ll j=1;j<=m;++j)a[i][j]=b[i][j];
}
int main(){
#ifdef cnyali_lk
    freopen("b.in","r",stdin);
    freopen("b.out","w",stdout);
#endif
    n=read();
    m=read();
    xmin=0x3f3f3f3f3f3f3f3f,xmax=0xcccccccccccccccc;
    for(ll i=1;i<=n;++i)for(ll j=1;j<=m;++j){a[i][j]=read();chkmin(xmin,a[i][j]);chkmax(xmax,a[i][j]);}
    ll ans=0x3f3f3f3f3f3f3f3f,l,r,mid;
    for(ll i=0;i<4;++i){
        l=0;
        r=ans-1;
        while(l<=r){
            mid=(l+r)>>1;
            if(check(mid))r=mid-1;
            else l=mid+1;
        }
        ans=r+1;
        rrotate();
    }
    printf("%lld\n",ans);
    
    return 0;
}

C

先考虑给定$a_i$无修改的情况。

欧拉定理 : 当$b\ge \varphi(p)$时,$a^b=a^{b\bmod \varphi(p)+\varphi(p)}$

所以可以通过计算$a^b\bmod p+[a^b\ge p]\cdot p$来计算答案。

大概就是:

int query(int l,int r,int p){
    if(l==r)return a[l]%p+(a[l]>=p)*a[l];
    return calc(a[l],query(l+1,r,phi(p)),p);
}

其中$calc(a,b,p)$表示计算$a^b\bmod p+[a^b\ge p]\cdot p$。

正确性显然吧。

但是太慢了。

我们发现,对$p$不断地做$p=\varphi(p)$,很快就会得到1,而1之后就没有必要再算了。

(据说是$O(\log n)$次?)(算出来当$p\le 2\cdot 10^7$时最多24次)

什么?区间修改?差分完直接树状数组维护就好了。

快速幂是$O(\log n)$的,树状数组也可以$O(\log n)$单点查询。

int query(int l,int r,int p){
    if(l==r||p==1)return a[l]%p+(a[l]>=p)*a[l];
    return calc(a[l],query(l+1,r,phi(p)),p);
}

时间复杂度$O(n\log^2 n) $。

标签: 贪心, 数论, 二分, 树状数组, 前缀和

添加新评论