acm 乘法逆元 或线段树 UVALive 5798

方法一:树状数组维护前缀和,运用乘法逆元求除以B的n次方mod P的值

方法二:线段树,保存了[l,r]之间的hash值


UVALive 5798


J - Jupiter Atacks!

Time Limit: 3000 MS      Memory Limit: 0 KB      64bit IO Format: %lld & %llu

Description

Download as PDF

Jupiter is invading! Major cities have been destroyed by Jovian spacecrafts and humanity is fighting back. Nlogonia is spearheading the counter-offensive, by hacking into the spacecrafts' control system.

Unlike Earthling computers, in which usually a byte has 28 possible values, Jovian computers use bytes with B possible values, { 0, 1,..., B- 1}. Nlogonian software engineers have reverse-engineered the firmware for the Jovian spacecrafts, and plan to sabotage it so that the ships eventually selfdestruct.

As a security measure, however, the Jovian spacecrafts run a supervisory program that periodically checks the integrity of the firmware, by hashing portions of it and comparing the result against known good values. To hash the portion of the firmware from the byte at position i to the byte at position j, the supervisor uses the hash function

Hf i,...,  f j) =  $\displaystyle \sum_{​{k=0}}^{​{j-i}}$ B k f j-k    ( mod   P)

where  P is a prime number. For instance, if  B = 20 and  P = 139, while bytes 2 to 5 of the firmware have the values  f2 = 14f3 = 2f4 = 2, and  f5 = 4, then


H(f2,..., f5)=B0f5 + B1f4 + B2f3 + B3f2    ( mod P)(1)
 =200x 4 + 201x 2 + 202x 2 + 203x 14    ( mod 139)(2)
 =4 + 40 + 800 + 112000    ( mod 139)(3)
 =112844    ( mod 139)(4)
 =115(5)

The Nlogonian cryptologists need to find a way to sabotage the firmware without tripping the supervisor. As a first step, you have been assigned to write a program to simulate the interleaving of two types of commands: editing bytes of the firmware by the Nlogonian software engineers, and computing hashes of portions of the firmware by the Jovian supervisory program. At the beginning of the simulation the value of every byte in the firmware is zero.

Input

Each test case is described using several lines. The first line contains four integers BPL and N, where B is the number of possible values of a Jovian byte, P is the modulus of the Jovian hash ( 2$ \le$B < P$ \le$109 and P prime), L is the length (number of Jovian bytes) of the spacecrafts' firmware, and N is the number of commands to simulate ( 1$ \le$LN$ \le$105). At the beginning of the simulation the value of every byte in the firmware is fi = 0 for 1$ \le$i$ \le$L. Each of the next N lines describes a command to simulate. Each command description starts with an uppercase letter that is either `E' or `H', with the following meanings.


`E$ \rightarrow$ The line describes an edit command. The letter is followed by two integers I and V indicating that the byte at position I of the firmware (that is, fI) must receive the value V ( 1$ \le$I$ \le$L and 0$ \le$V$ \le$B - 1).


`H$ \rightarrow$ The line describes a hash command. The letter is followed by two integers I and J indicating that H(fI,..., fJ) must be computed ( 1$ \le$I$ \le$J$ \le$L).


The last test case is followed by a line containing four zeros.

Output

For each test case output the results of the hash commands in the input. In the i-th line write an integer representing the result of the i-th hash command. Print a line containing a single character `-' (hyphen) after each test case.

Sample Input

20 139 5 7
E 1 12
E 2 14
E 3 2
E 4 2
E 5 4
H 2 5
E 2 14
10 1000003 6 11
E 1 3
E 2 4
E 3 5
E 4 6
E 5 7
E 6 8
H 1 6
E 3 0
E 3 9
H 1 3
H 4 6
999999935 999999937 100000 7
E 100000 6
E 1 7
H 1 100000
E 50000 8
H 1 100000
H 25000 75000
H 23987 23987
0 0 0 0

Sample Output

115
-
345678
349
678
-
824973478
236724326
450867806
0
-

方法一:乘法逆元

/*
 * Author:  nick wong
 * Created Time:  2014年08月24日 星期日 16时19分28秒
 * File Name: j.cpp
 */
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<stack>
using namespace std;
#define out(x) cout<<#x<<": "<<x<<endl
const double eps(1e-8);
const int maxn=10100;
const long long maxint=-1u>>1;
const long long maxlong=maxint*maxint;
typedef long long lint;

lint f[100100],un[100100],Pow[100100];
lint B,P;
int L,N;

lint ex_gcd(lint a,lint b,lint &x,lint &y){
	if (a==0&&b==0) return -1;
	if (b==0){x=1;y=0;return a;}
	lint d=ex_gcd(b,a%b,y,x);
	y-=a/b*x;
	return d;
}

lint mod_re(lint a,lint n){
	lint x,y;
	lint d = ex_gcd(a,n,x,y);
	return (x%n+n)%n;
}

int lowb(int x){ return (x)&(-x);}

void change(int x,lint now){
		while (x<=L){
			f[x] = ((f[x]+now)%P+P)%P;
			x += lowb(x);
		}
}

lint find(int x){
	if (x==0) return 0;
	lint tot = 0;
	while (x){
		tot = ((tot+f[x])%P+P)%P;
		x -= lowb(x);
	}
	return tot;
}

int main()
{

	while (cin>>B>>P>>L>>N){
	    if (B+P+L+N==0) break;	
		lint tmp = 1;
		un[L] = 1;
		Pow[L] = 1;
		memset(f,0,sizeof(f));
		for (int i =L-1; i >0; i -- ){
			tmp = (tmp*B) % P;
			un[i] = mod_re(tmp,P);
			Pow[i] = tmp;
		}		
		getchar();
		for (int i = 1; i <= N; i ++){
			char ch;
			int l,r;
			scanf("%c %d %d%*c",&ch,&l,&r);
			//cout<<ch<<" "<<endl;
			//out(l); out(r);
			if (ch=='E'){
				lint now = find(l)-find(l-1);
				now -= Pow[l]*r;
			    change(l,-now);	
			} else 
			if (ch=='H') {
				lint ans  = ((find(r)-find(l-1))%P+P)%P;
				ans = (ans*un[r])%P;
				printf("%lld\n",ans);
				//cout<<ans<<endl;
			}
		}
		printf("-\n");
	}
    return 0;
}



方法二:线段树

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 100011

long long sum[4*maxn],pw[maxn];
long long P,B;

void update(int i,int l,int r,int a,int b)
{
    if (l==r) sum[i]=b;
    else
    {
        int mid=(l+r)>>1;
        if (a<=mid) update(i<<1,l,mid,a,b);
        else update((i<<1)|1,mid+1,r,a,b);
        sum[i]=(sum[(i<<1)|1]+(pw[r-mid]*sum[i<<1])%P)%P;
    }
}

long long query(int i,int l,int r,int a,int b)
{
    if (l==a&&r==b) return sum[i];
    int mid=(l+r)>>1;
    if (b<=mid) return query(i<<1,l,mid,a,b);
    if (a>mid) return query((i<<1)|1,mid+1,r,a,b);
    long long tmp1=query(i<<1,l,mid,a,mid),
              tmp2=query((i<<1)|1,mid+1,r,mid+1,b);
    return ((tmp1*pw[b-mid])%P+tmp2)%P;
}

int main()
{
    int L,N,a,b;
    char s[5];
    while (scanf("%d%lld%d%d",&B,&P,&L,&N)!=EOF&&(B||P||L||N))
    {
        memset(sum,0,sizeof(sum));
        pw[0]=1;
        for (int i=1;i<=L;i++) pw[i]=(pw[i-1]*B)%P;
        while (N--)
        {
            scanf("%s%d%d",s,&a,&b);
            if (s[0]=='E') update(1,1,L,a,b);
            else printf("%lld\n",query(1,1,L,a,b));
        }
        puts("-");
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值