题目意思百度上到处都是啊~
题目大意:
有一个特殊的计算器,初始值 X = 1。现在有两种操作:
1. 乘以 Y
2. 除以一个之前乘过的数。
每次操作之后,输出对 M 取余的值。
方法1(错误):
根据题目意思,用同余计算。
但是这里的要取余的数字是不是素数!所以这个方法不对
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <math.h> #include <vector> #include <map> #include <stack> #include <algorithm> #include <vector> using std::cin; using std::cout; using std::endl; using std::sort; using std::min; using std::max; using std::vector; #define LL long long LL n, mod; const int MAXN = 100000 + 1000; LL a[MAXN]; LL exgcd(LL a,LL b,LL &x,LL &y) { if(b==0) { x=1; y=0; return a; } LL r=exgcd(b,a%b,x,y); LL t=x; x=y; y=t-a/b*y; return r; } /* bool modular_linear_equation(LL a,LL b,LL n) { LL x,y,x0,i; LL d=exgcd(a,n,x,y); if(b%d) return false; x0=x*(b/d)%n; //特解 cout<<"!"<<d<<endl; for(i=1;i<d;i++) printf("%d\n",(x0+i*(n/d))%n); return true; } */ LL modular_linear_equation(LL a,LL b,LL n) { LL x,y,x0,i; LL d=exgcd(a,n,x,y); if(b%d) { while (1) { cout<<"!!"<<endl; } } //无解,但是这个题不可能的 x0=x*(b/d)%n; //特解 // x0 = (x0 + n) % n; return x0; } int main() { //cout<<modular_linear_equation(1, 2, 100); //return 0; //freopen("a.txt","w",stdout); int ttt; scanf("%d", &ttt); for (int j = 1; j <= ttt; ++ j) { printf("Case #%d:\n", j); scanf("%I64d%I64d", &n, &mod); LL now = 1LL; int tot = 0; //存在多少个整数倍 for (int i = 1; i <= n ; ++ i) //要修改 { LL flag; scanf("%I64d%I64d", &flag, &a[i]); if (now == 0 && tot == 0) now = mod; if (flag == 1LL) { if (a[i] % mod == 0) ++tot; else now = (now * a[i]) % mod; if (now == 0) tot ++; } if (flag == 2LL) { LL A = a[a[i]]; if (A % mod == 0) { --tot; goto xxx;//如果去掉了一个整数倍的,不用计算 } if (mod % A == 0) --tot; LL B = now; LL willnow = modular_linear_equation(A, B, mod); now = willnow % mod; } xxx:; now = now % mod; if (tot) printf("0\n"); else printf("%I64d\n", now); } } return 0; }
方法2:线段树
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> using std::cin; using std::cout; using std::endl; using std::min; using std::max; #define LL long long int n; LL mod; struct node { int L, R; LL key; int ls,rs; void clear() { key = 1; } node():key(1),L(-1),R(-1), ls(-1), rs(-1){} }t[100000 * 2 + 200]; int tail=0; void make_tree(int now, int ll, int RR) { t[now].L = ll; t[now].R = RR; t[now].key = 1; //全部都为1 if (ll == RR) return; int mid = (ll + RR) / 2; t[now].ls = ++ tail; make_tree(tail, ll, mid); t[now].rs = ++ tail; make_tree(tail, mid + 1, RR); } LL change_tree(int now, int k, LL p) //在k位置改为p { if (t[now].L == k && t[now].R == k) { t[now].key = p; return p; } int mid = (t[now].L + t[now].R) / 2; if (k <= mid) change_tree(t[now].ls, k, p); if (mid < k) change_tree(t[now].rs, k, p); LL a = t[t[now].ls].key; LL b = t[t[now].rs].key; t[now].key = (a * b) % mod; return (a * b) % mod; } int main() { int tt, tmp; scanf("%d", &tt); make_tree(0, 1, 100001); for (int ttt = 1; ttt <= tt; ++ ttt) { for (int i = 0; i != tail + 10; ++ i) t[i].clear();//tree init printf("Case #%d:\n", ttt); scanf("%d%I64d", &n, &mod); for (int i = 1; i <= n; ++ i) { int flag; LL num; scanf("%d%I64d", &flag, &num); if (flag == 1) cout << change_tree(0, i, num); else cout << change_tree(0, num, 1) ; cout << endl; } } return 0; }
方法3:平衡树。
类似平衡树维护总和的方法,来维护一颗平衡树的积。
比赛时候一个int没改为LL所以错了,这让我十分十分的忧伤!不然就区域赛出线了,哎。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <math.h> #include <vector> #include <map> #include <stack> #include <algorithm> #include <vector> #pragma comment(linker, "/STACK:102400000,102400000") using std::cin; using std::cout; using std::endl; using std::sort; using std::min; using std::max; using std::vector; #define LL long long LL n, mod; const int MAXN = 200010; struct Size_Balabced_Tree{ int left[MAXN],right[MAXN],s[MAXN],root,tt; LL w[MAXN], key[MAXN]; void clear(){ memset(left,0,sizeof(left)); memset(right,0,sizeof(right)); memset(s,0,sizeof(s)); for (int i = 0; i != MAXN; ++ i) w[i] = key[i] = 1; root=tt=0; } void gr(int &t){ int k=left[t]; left[t]=right[k]; right[k]=t; s[k]=s[t]; w[k] = w[t]; // s[t]=s[left[t]]+s[right[t]]+1; w[t] = ((w[left[t]] * w[right[t]])%mod * key[t]) % mod;// t=k; } void gl(int &t){ int k=right[t]; right[t]=left[k]; left[k]=t; s[k]=s[t]; s[t]=s[left[t]]+s[right[t]]+1; w[k] = w[t];// w[t] =(( w[left[t]] * w[right[t]]) % mod * key[t]) % mod; t=k; } void _insert(int &t,LL v){ if (!t){ t=++tt; key[t]=v; w[t] = v; // s[t]=1; return ; } ++s[t]; w[t] = (w[t] * v) % mod; if (v<key[t]){ _insert(left[t],v); if (s[left[left[t]]]>s[right[t]]) gr(t); } else{ _insert(right[t],v); if (s[right[right[t]]]>s[left[t]]) gl(t); } w[t] = ((w[left[t]] * w[right[t]] % mod ) * key[t] ) % mod; } LL _dele(int &t,LL v){ LL ans; --s[t]; if (v==key[t] || v<key[t] && !left[t] || v>key[t] && !right[t]) { ans=key[t]; if (!left[t] || !right[t]) t=left[t]+right[t]; else key[t]=_dele(left[t],v+1); } else if (v<key[t]) ans=_dele(left[t],v); else ans=_dele(right[t],v); w[t] = ((w[left[t]] * w[right[t]] % mod)* key[t]) % mod;// return ans; } bool _find(int &t,LL v){ if (!t) return false; if (key[t]==v) return true; if (v<key[t]) return _find(left[t],v); else return _find(right[t],v); } LL _rank(int &t,LL v){ //查v的排名 if (t==0) return 1; if (v<=key[t]) return _rank(left[t],v); else return s[left[t]]+1+ _rank(right[t],v); } LL _selectmintomax(int &t,LL k){ //查第k名 (从小到大) if (k==s[left[t]]+1) return key[t]; if (k<=s[left[t]]) return _selectmintomax(left[t],k); else return _selectmintomax(right[t],k-1-s[left[t]]); } int _selectmaxtomin(int &t,int k){ //查第k名 从大到小排名 if (k==s[right[t]]+1) return key[t]; if (k<=s[right[t]]) return _selectmaxtomin(right[t],k); else return _selectmaxtomin(left[t],k-1-s[right[t]]); } int _pred(int &t,int v){ //找比v小的最大的 找不到就返回自己 int ans; if (t==0) return v; if (v<=key[t]) ans=_pred(left[t],v); else{ ans=_pred(right[t],v); if (ans==v) ans=key[t]; } return ans; } int _succ(int &t,int v){ //找比v大的最小的数字 找不到返回自己 int ans; if (t==0) return v; if (v>=key[t]) ans=_succ(right[t],v); else { ans=_succ(left[t],v); if (ans==v) ans=key[t]; } return ans; } void insert(int k){ //插入K _insert(root,k); } bool find(int k){ //查找K,返回ture false return _find(root,k); } int dele(int k){ //删除K,如果有就删掉,没有就删掉遍历到的最后一个数字,并且返回这个数字(你可以重新插入) return _dele(root,k); } int rank(int k){ //查找K在树种的排名,从小到大排名 return _rank(root,k); } int selectmintomax(int k){ //插找第K小元素 return _selectmintomax(root,k); } int selectmaxtomin(int k){ //查找第K大元素 return _selectmaxtomin(root,k); } int pred(int k){ //找比K小的最大的数字 return _pred(root,k); } int succ(int k){ //找比K大的最小的数字 return _succ(root,k); } }SBT; LL a[MAXN]; void pg() { cout<<"root="<<SBT.root<<endl; for (int i = 0; i <= 15; ++ i) { cout <<" i="<<i<<" left="<< SBT.left[i] <<" right=" <<SBT.right[i] <<" s=" << SBT.s[i] << " key="<< SBT.key[i]<<" w="<<SBT.w[i]<<endl; } } int main() { // int size = 256 << 20; // 256MB //char *p = (char*)malloc(size) + size; // __asm__("movl %0, %%esp\n" :: "r"(p)); //freopen("a.txt","w",stdout); int ttt; scanf("%d", &ttt); for (int j = 1; j <= ttt; ++ j) { printf("Case #%d:\n", j); SBT.clear(); SBT.insert(1); scanf("%I64d%I64d", &n, &mod); for (int i = 1; i <= n ; ++ i) //要修改 { LL flag; scanf("%I64d%I64d", &flag, &a[i]); if (flag == 1) SBT.insert(a[i]); if (flag == 2) SBT.dele(a[a[i]]); printf("%I64d\n", (SBT.w[SBT.root]) % mod); } //pg(); } return 0; }