185div1D题

解题报告:

Consider a number x. If we apply an assignmentx = x3,x becomes x3. If we apply such assignment once more, we will get(x3)3 = x32. If we apply such assignmentk times, we will get x3k.

Thus, we can get such a sequence a0 = x, a1 = x3, a2 = x32, ..., ak = x3k, ....

Consider a prime p. From Fermat's Little Theorem, we can getxp - 1 = 1(mod p). Further more, we can get xy = xymod(p - 1)(modp), here amod b means the remainder

 of a divided by b.

推论证明:

令y=n(p-1)+r,0<=r<p-1, 则x^y=x^(n(p-1))*x^r
x^(n(p-1))=1 mod p

Fortunately, 348 = 1(mod(95542721 - 1)), thus, x3k = x3kmod48(modp). In other words, ak = ak + 48, which means the cycle of the sequence isT = 48.

Let's come back to the topic. Each time we run a 1-type query, for every i in the range [l, r], we apply such an assignmentai = ai3. At any moment somei has been applied 48 times such assignments, we can consider thisi hasn't been applied any assignments before.

We can use segment tree to solve this problem. Every node of the segment tree maintains some information: the times that we applied assignments in the node's whole range(it's a lazy tag), current sum of the node's corresponding range and the sum of the node's range after we applied assignments k(1 ≤ k < 48) times.

In such a way, we can solve the problem in O(n·T + q·T·logn) time.

If you do not realize how to maintain the segment tree clearly, you can view the code3782263.

贴个我的超时代码:下附神牛代码。

/*

线段树:使用延迟标记,下传叠加 。
使用 mark 标记该节点下的子节点是否存在没有处理的 数值、

此题还有一定的数论知识,详细看上文解题报告。 

*/
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;

#define mod 95542721
#define manx 100009
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1

__int64 a[manx],root[manx<<2],sum;

int s[manx<<2];
bool mark[manx<<2];

void up(int rt) {  
    root[rt]=root[rt<<1]+root[rt<<1|1]; 
    if(mark[rt<<1] || mark[rt<<1|1]) mark[rt]=1;
    else mark[rt] = 0;
}

void make(int l,int r,int rt){
    s[rt] = 0;
    mark[rt] = 0;
    if(l==r){ root[rt]=a[l]; return ;}
    int mid=(l+r)>>1;
    make(lson);
    make(rson);
    up(rt);
}

void update(int L,int R,int l,int r,int rt){
    mark[rt]=1;
    if(L<=l && r<=R) { s[rt]++;  return; }
    int mid =(l+r)>>1;
    if(R<=mid) update(L,R,lson);
    else if(L>mid) update(L,R,rson);
    else {
        update(L,mid,lson);
        update(mid+1,R,rson);
    }
}

void query(int L,int R,int l,int r,int rt){
    if(L<=l && r<=R) { sum+=root[rt]; sum%=mod;  return ; }
    int mid = (l+r)>>1;
    if(R<=mid) query(L,R,lson);
    else if(L>mid) query(L,R,rson);
    else {
        query(L,mid,lson);
        query(mid+1,R,rson);
    }
}

void operate(int rt){
    for(int i=1;i<=s[rt];i++) 
        root[rt]=root[rt]*root[rt]%mod*root[rt]%mod;
    s[rt]=0;
    mark[rt]=0;
    return ; 
}

void down(int L,int R,int l,int r,int rt){
    if(!mark[rt]) return;
    if(l==r && l<=R && l>=L ) { operate(rt); return; }
    if(l==r) return; 
    if(s[rt]) {
        s[rt<<1]+=s[rt];
        s[rt<<1|1]+=s[rt];
        s[rt]=0;
        mark[rt<<1] = mark[rt<<1|1] = 1;/
    }
    int mid=(l+r)>>1;
    if(R<=mid) down(L,R,lson);
    else if(L>mid) down(L,R,rson);
    else {
        down(L,mid,lson);
        down(mid+1,R,rson);
    }
    up(rt);
}

int main(){
    int n,q;
    while(scanf("%d",&n)!=EOF){
        for(int i=1;i<=n;i++) scanf("%I64d",&a[i]);
        make(1,n,1);
        scanf("%d",&q);
        int type,l,r;
        for(int i=0;i<q;i++){
            scanf("%d%d%d",&type,&l,&r);
            sum = 0;
            if(type==2) update(l,r,1,n,1);
            if(type==1) {
                down(l,r,1,n,1);
                query(l,r,1,n,1);
                printf("%I64d\n",sum);
            }    
        }
    }
}
/*

8
1 2 3 4 5 6 7 8
12
1 2 5
2 2 5
1 2 5
2 3 6
1 4 7

*/


正确代码:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<ctime>
#include<iostream>
#include<sstream>
#include<algorithm>
#include<string>
#include<bitset>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<iomanip>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int,int> pii;
typedef pair<ld,ld> pdd;
typedef pair<ll,ll> pll;

#define X first
#define Y second

const int MaxN=100010;
const int MOD=95542721;
const int LEN=48;

int n;
int a[MaxN];

struct node
{
	node *Lc,*Rc;
	int L,R,m;
	int p;
	int v[LEN];
	node (int x,int y)
	{
		L=x;
		R=y;
		m=(L+R)>>1;
		p=0;
		Lc=Rc=0;
		memset(v,0,sizeof(v));
	}
};

node *root;
int tmp[LEN];

int mod(int x,int MOD)
{
	while (x>=MOD) x-=MOD;
	return x;
}

void update(node *it)
{
	for (int i=0;i<LEN;++i)
		it->v[i]=mod(it->Lc->v[i]+it->Rc->v[i],MOD);
}

void clear(node *it)
{
	if (!it->p) return;
	memcpy(tmp,it->Lc->v,sizeof(tmp));
	for (int i=0;i<LEN;++i)
		it->Lc->v[i]=tmp[mod(i+it->p,LEN)];
	it->Lc->p=mod(it->Lc->p+it->p,LEN);
	memcpy(tmp,it->Rc->v,sizeof(tmp));
	for (int i=0;i<LEN;++i)
		it->Rc->v[i]=tmp[mod(i+it->p,LEN)];
	it->Rc->p=mod(it->Rc->p+it->p,LEN);
	it->p=0;
}

node *build(int L,int R)
{
	node *it=new node(L,R);
	if (L<R)
	{
		it->Lc=build(L,it->m);
		it->Rc=build(it->m+1,R);
		update(it);
	}
	else
	{
		int t=a[L];
		for (int i=0;i<LEN;++i)
		{
			it->v[i]=t;
			t=(ll)t*t%MOD*t%MOD;
		}
	}
	return it;
}

int query(node *it,int L,int R)
{
	if (it->L==L&&it->R==R)
		return it->v[0];
	clear(it);
	if (R<=it->m)
		return query(it->Lc,L,R);
	if (L>it->m)
		return query(it->Rc,L,R);
	return mod(query(it->Lc,L,it->m)+query(it->Rc,it->m+1,R),MOD);
}

void modify(node *it,int L,int R)
{
	if (it->L==L&&it->R==R)
	{
		it->p++;
		memcpy(tmp,it->v,sizeof(tmp));
		for (int i=0;i<LEN;++i)
			it->v[i]=tmp[mod(i+1,LEN)];
		return;
	}
	clear(it);
	if (R<=it->m)
		modify(it->Lc,L,R);
	else if (L>it->m)
		modify(it->Rc,L,R);
	else
	{
		modify(it->Lc,L,it->m);
		modify(it->Rc,it->m+1,R);
	}
	update(it);
}

void init()
{
	cin>>n;
	for (int i=1;i<=n;++i)
	{
		scanf("%d",&a[i]);
		a[i]%=MOD;
	}
	root=build(1,n);
}

void work()
{
	int T;
	cin>>T;
	while (T--)
	{
		int flag,x,y;
		scanf("%d%d%d",&flag,&x,&y);
		if (flag==1)
			printf("%d\n",query(root,x,y));
		else
			modify(root,x,y);
	}
}

int main()
{
	init();
	work();
	return 0;
}


 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值