CodeForces906D

题意:

给定一个数列和模数p,每次询问一个区间[l,r],求的值。其中

思路:

有扩展欧拉定理:

由欧拉定理,有,所以上式可以简单记为:

比如

其中

其中

可以一直递归下去,可以递归处理。

如果l==r的时候,返回的是

所以定义一个新的Mod方式:a<b?a:a%b+b。

递归的终点就是Mod(a[l],mod)。

如果,那么嵌套层数为

如果了,那么可以在第二个式子返回0,之后都不用再继续递归了,这也是一个递归终点。

回溯的时候就可以用快速幂来计算了,比如先回溯到第三个式子,用正常的快速幂是ojbk的,但是回溯到第二个式子的时候会发现只计算了这一部分,无法判断,所以用新定义的Mod方式来进行快速幂运算,这样子每次在函数中调用快速幂的时候得到的就是整个的值啦,体现在式子里面就相当于改变了这个快速幂的方式,那么返回的就是整个上上式的值啦。

注意计算的时候要记忆化。

这里有个坑点,求的时候,如果调用参数列表里的参数的话会TLE,如果自己在函数内部传个参,就不会TLE了,为什么时间差这么多这是什么玄学啊,难道用函数内部的变量更快?这还是第一次见这种状况。

代码:

#define Mod(a,b) a<b?a:a%b+b
typedef long long ll;
int n,l,r,q;
ll m;
ll a[100100];
map<ll,ll>phi;
ll euler(ll n)
{
    if(phi[n]!=0)return phi[n];
    ll i,res=n;
    ll temp=res;//传个参就不会TLE了???(迷
    for(i=2;i*i<=n;i++)
    {
        if(n%i==0)
        {
            res=res/i*(i-1);
            while(n%i==0)
                n=n/i;
        }
    }
    if(n>1)res=res/n*(n-1);
    phi[temp]=res;//直接phi[n]会TLE
    return res;
}
ll PowerMod(ll a,ll b,ll c)
{
    ll ans=1;
    a=Mod(a,c);
    while(b>0)
    {
        if(b&1)
            ans=Mod(ans*a,c);
        b>>=1;
        a=Mod(a*a,c);
    }
    return ans;
}
ll solve(int l,int r,ll mod)
{
    if(l==r||mod==1)return Mod(a[l],mod);
    return PowerMod(a[l],solve(l+1,r,euler(mod)),mod);
}
int main()
{
    scanf("%d%lld",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    scanf("%d",&q);
    while(q--)
    {
        scanf("%d%d",&l,&r);
        printf("%lld\n",solve(l,r,m)%m);//记得这里还是要%m
    }
    return 0;
}
牛客练习赛22E

题意:

多了一个区间[l,r]加上x的操作,每次查询的模p也在改变(p <= 2e7)。

思路:

套个树状数组或者线段树都可以,这里要先线性筛出欧拉函数。

代码:

#define Mod(a,b) a<b?a:a%b+b
typedef long long ll;
int n;
#define MAXN 20000001
ll eu[MAXN];
ll pri[MAXN];
bool vis[MAXN];
void init()
{
    eu[1]=1;
    ll cnt=0;
    for(ll i=2;i<MAXN;i++)
    {
        if(!vis[i]){pri[cnt++]=i;eu[i]=i-1;}
        for(int j=0;j<cnt&&pri[j]*i<MAXN;j++)
        {
            vis[i*pri[j]]=1;
            if(i%pri[j]==0)
            {
                eu[i*pri[j]]=eu[i]*pri[j];
                break;
            }
            eu[i*pri[j]]=eu[i]*(pri[j]-1);
        }
    }
}
ll c[500010];
int lowbit(int x)
{
    return x&(-x);
}
ll query(int x)
{
    ll res=0;
    while(x)
    {
        res+=c[x];
        x-=lowbit(x);
    }
    return res;
}
void add(int x,ll v)
{
    while(x<=n)
    {
        c[x]+=v;
        x+=lowbit(x);
    }
}
ll PowerMod(ll a,ll b,ll c)
{
    ll ans=1;
    a=Mod(a,c);
    while(b>0)
    {
        if(b&1)
            ans=Mod(ans*a,c);
        b>>=1;
        a=Mod(a*a,c);
    }
    return ans;
}
ll solve(int l,int r,ll mod)
{
    if(l==r||mod==1)return Mod(query(l),mod);
    return PowerMod(query(l),solve(l+1,r,eu[mod]),mod);
}
int main()
{
    int l,r,q,op;
    ll m;
    init();
    scanf("%d%d",&n,&q);
    memset(c,0,sizeof(c));
    ll ls=0;
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&m);
        add(i,m-ls);
        ls=m;
    }
    while(q--)
    {
        scanf("%d%d%d%lld",&op,&l,&r,&m);
        if(op==1)
        {
            add(l,m);
            add(r+1,-m);
        }
        else if(op==2)printf("%lld\n",solve(l,r,m)%m);
    }
    return 0;
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

HDU5649 二分+线段树 Previous
LOJ515 & 51nod1573 Bitset乱搞 Next