zoukankan      html  css  js  c++  java
  • 2017六省联考 相逢是问候

    题目链接:戳我

    落谷时间卡得真紧。。。。test9 和test11 根本过不去,只有在BZOJ上面A掉了。。。。。。

    首先可以看得出这是一个线段树维护的数据结构题目吧qwqwq

    但是对于这种阶乘修改,显然是不具备可加性的,所以我们只能暴力修改。。。。但是暴力修改时间复杂度是会炸天的!

    但是我们再看一下——

    (c^{a[i]^{a[i]^{...}}} pmod p)
    我们想到了什么!!!——拓展欧拉定理啊qwqwq

    [a^bequivegin{cases}a^{b\%phi(p)}&{gcd(a,p)=1}\a^b&{gcd(a,p)1,blephi(p)}\a^{b\%phi(p)+phi(p)}&gcd(a,p) eq1,bgephi(p)end{cases}pmod p ]

    (其实大家可以先去看看【上帝与集合的正确用法】这个题,想必是有一些启发的)

    根据拓展欧拉定理,显然我们递归几次这个模数就会变成1,当模数变成1的时候,显然就不需要再次计算了。

    举个例子:

    [c^{a[i]^{a[i]}}=c^{a[i]^{a[i]\%phi(phi(p))+phi(phi(p))}+phi(p)} ]

    所以我们可以预先处理出来p的phi值都是多少,结束条件为phi值==1。

    代码如下:

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #define MAXN 100010
    using namespace std;
    int n,m,c,p,cnt;
    int a[MAXN],phi[MAXN];
    struct Node{int l,r,tot,sum;}t[MAXN<<2];
    
    inline int Phi(int x)
    {
    	long long cur_ans=x;
    	int now=x;
    	for(int i=2;i*i<=now;i++)
    	{
    		if(now%i==0) cur_ans=cur_ans/i*(i-1);
    		while(now%i==0) now/=i;
    	}
    	if(now>1) cur_ans=cur_ans/now*(now-1);
    	return cur_ans;
    }
    
    inline void init()
    {
    	int cur=p;
    	while(cur>1)
    	{
    		cur=Phi(cur);
    		phi[++cnt]=cur;
    	}
    	//for(int i=1;i<=cnt;i++) printf("phi[%d]=%d
    ",i,phi[i]);
    }
    
    inline long long fpow(long long x,long long y,long long mod)
    {
    	long long cur_ans=1;
    	int flag1=0,flag2=0;
    	while(y)
    	{
    		if(y&1) cur_ans=cur_ans*x,flag1|=flag2;
    		if(cur_ans>=mod) flag1=1,cur_ans%=mod;
    		x=x*x;
    		if(x>=mod) flag2=1,x%=mod;
    		y>>=1;
    	}
    	if(flag1) cur_ans+=mod;
    	return cur_ans;
    }
    
    inline long long solve(int l,int r,long long x,long long mod)
    {
    	if(l==r) return x;
    	return fpow(c,solve(l+1,r,x,phi[l+1]),mod);
    }
    
    inline int ls(int x){return x<<1;}
    
    inline int rs(int x){return x<<1|1;}
    
    inline void push_up(int x)
    {	
    	t[x].sum=(t[ls(x)].sum+t[rs(x)].sum)%p;
    	t[x].tot=min(t[ls(x)].tot,t[rs(x)].tot);
    }
    
    inline void build(int x,int l,int r)
    {
    	t[x].l=l,t[x].r=r;
    	if(l==r){t[x].sum=a[l];return;}
    	int mid=(l+r)>>1;
    	build(ls(x),l,mid);
    	build(rs(x),mid+1,r);
    	push_up(x);
    }
    
    inline void update(int x,int ll,int rr)
    {
    	if(t[x].tot>cnt) return;
    	int l=t[x].l,r=t[x].r;
    	if(l==r)
    	{
    		t[x].sum=solve(0,++t[x].tot,a[l],p)%p;
    		return;
    	}
    	int mid=(l+r)>>1;
    	if(ll<=mid) update(ls(x),ll,rr);
    	if(mid<rr) update(rs(x),ll,rr);
    	push_up(x);
    }
    
    inline long long query(int x,int ll,int rr)
    {
    	int l=t[x].l,r=t[x].r;
    	if(ll<=l&&r<=rr) return t[x].sum%p;
    	int mid=(l+r)>>1;
    	long long cur_ans=0;
    	if(ll<=mid) cur_ans=(cur_ans+query(ls(x),ll,rr))%p;
    	if(mid<rr) cur_ans=(cur_ans+query(rs(x),ll,rr))%p;
    	return cur_ans;
    }
    
    int main()
    {
    	#ifndef ONLINE_JUDGE
    	freopen("ce.in","r",stdin);
    	#endif
    	scanf("%d%d%d%d",&n,&m,&p,&c);
    	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    	build(1,1,n);
    	init();
    	//for(int i=1;i<=cnt;i++) printf("%d
    ",phi[i]);
    	for(int i=1;i<=m;i++)
    	{
    		int op,l,r;
    		scanf("%d%d%d",&op,&l,&r);
    		if(op==0) update(1,l,r);
    		else printf("%lld
    ",query(1,l,r));
    	}
    	return 0;	
    }
    
  • 相关阅读:
    java多线程(同步与死锁问题,生产者与消费者问题)
    剑指OFFER之跳台阶(九度OJ1388)
    剑指OFFER之二维数组中的查找(九度OJ1384)
    剑指OFFER之旋转数组的最小数字(九度OJ1386)
    我所思考的生活,致半年后的自己
    剑指OFFER之用两个栈实现队列(九度OJ1512)
    剑指OFFER之二维数组中的查找(九度OJ1384)
    剑指OFFER之重建二叉树(九度OJ1385)
    简单的客户机服务器投射模拟
    网络复习之TCP
  • 原文地址:https://www.cnblogs.com/fengxunling/p/10501979.html
Copyright © 2011-2022 走看看