题目:
One day, a useless calculator was being built by Kuros. Let's assume that number X is showed on the screen of calculator. At first, X = 1. This calculator only supports two types of operation.
1. multiply X with a number.
2. divide X with a number which was multiplied before.
After each operation, please output the number X modulo M.
Input
The first line is an integer T(1≤T≤101≤T≤10), indicating the number of test cases.
For each test case, the first line are two integers Q and M. Q is the number of operations and M is described above. (1≤Q≤105,1≤M≤1091≤Q≤105,1≤M≤109)
The next Q lines, each line starts with an integer x indicating the type of operation.
if x is 1, an integer y is given, indicating the number to multiply. (0<y≤1090<y≤109)
if x is 2, an integer n is given. The calculator will divide the number which is multiplied in the nth operation. (the nth operation must be a type 1 operation.)
It's guaranteed that in type 2 operation, there won't be two same n.
Output
For each test case, the first line, please output "Case #x:" and x is the id of the test cases starting from 1.
Then Q lines follow, each line please output an answer showed by the calculator.
Sample Input
1 10 1000000000 1 2 2 1 1 2 1 10 2 3 2 4 1 6 1 7 1 12 2 7
Sample Output
Case #1: 2 1 2 20 10 1 6 42 504 84
题目大意:有T组测试样例,每个样例给出n个操作,起始值为sum=1,每个操作对应两个数 x y,当x==1时,用当前的sum值乘以y;当x==2时,用当前的sum值除以第x次操做乘的那个值。每次操作,输出一次结果,注意最后结果要对m取余。
思路:对于乘法来说简单,因为遵循同余法则。注意除法不遵循同余法则。但是有些结果没法表示,再进行除法运算。
可以这样考虑,开一个数组a[],对于第x次操作,若x==1,则a[x]=y;若x==2,则a[x]=1,并且a[y]=1,然后再从第一个依次乘,这样就可得到结果。
暴力法代码(没想到能过,不超时)。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<vector>
#define ll long long
using namespace std;
int t;
int q;
const int INF=1e5+5;
int m;
ll sum;
int a[INF];
int main()
{
cin>>t;
int s=0;
while(t--)
{
s++;
sum=1;
scanf("%d%d",&q,&m);
int i,j,k,l;
printf("Case #%d:\n",s);
for(i=1;i<=q;i++)
{
scanf("%d%d",&j,&k);
if(j==1){
sum=sum*k%m;
a[i]=k;
printf("%d\n",sum);
}
else{//很关键
a[k]=1;a[i]=1;
sum=1;
for(l=1;l<=i;l++)
{
sum=sum*a[l]%m;
}
printf("%d\n",sum);
}
}
}
return 0;
}
线段树:思路也是那样,只是将那个过程转化到线段树中去了。
AC代码:
#include<iostream>//注意用long long 型,int型没过
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<vector>
#define ll long long
using namespace std;
int t;
ll q,m;
const int INF=1e5+5;
struct node{
ll left;
ll right;
ll sum;
}f[4*INF];
void build(ll ans,ll l,ll r){
f[ans].left =l;f[ans].right =r;
f[ans].sum =1;
if(l==r)return;
ll mid=(l+r)/2;
build(ans<<1,l,mid);
build(ans<<1|1,mid+1,r);
}
void update(ll ans,ll l,ll x){
if(f[ans].left ==l&&f[ans].right ==l)
{
f[ans].sum =x%m;return;
}
ll mid=(f[ans].left +f[ans].right )/2;
if(l<=mid)update(ans<<1,l,x);
else {
update(ans<<1|1,l,x);
}
f[ans].sum =f[ans<<1].sum*f[ans<<1|1].sum%m;
}
ll getsum(ll ans,ll l,ll r)
{
if(f[ans].left ==l&&f[ans].right ==r)
{
return f[ans].sum ;
}
ll mid=(f[ans].left +f[ans].right )/2;
if(r<=mid){
return getsum(ans<<1,l,r);
}
else if(l>mid)
{
return getsum(ans<<1|1,l,r);
}
else {
return getsum(ans<<1,l,mid)*getsum(ans<<1|1,mid+1,r)%m;
}
}
int main()
{
int s=0;
cin>>t;
while(t--)
{
s++;
scanf("%lld%lld",&q,&m);
build(1,1,q);
ll i,j,k;
ll val;
printf("Case #%d:\n",s);
for(i=1;i<=q;i++)
{
scanf("%lld%lld",&j,&k);
if(j==1)
{
update(1,i,k);
val=getsum(1,1,i);
printf("%lld\n",val);
}
else {
update(1,k,1);
val=getsum(1,1,i);
printf("%lld\n",val);
}
}
}
return 0;
}