hdu 5152 A Strange Problem(题意分析)线段树+欧拉函数

*****************************************BC题解**********************************************************************
1003 A Strange Problem 对于操作二,利用公式 当x >= Phi(C), A^x = A ^ (x%Phi(C) + Phi(C)) (mod C) 对于2333333这个模数来说,求18次欧拉函数后就变成了1,所以只需要保存19层第三次操作的加数即可,然后就直接是线段树区间更新和询问操作了。 Ps:很多人把题目想简单了,操作二不能直接简单的更新,不满足2^(2^x) mod P = 2^( 2^x mod P) mod P。
*********************************************************************************************************************
看了一下数论,终于明白什么意思了,数学功底差+书看的少就是捉急。
讨论里边看人问A不了,问题出在哪里,答曰2333333。当成笑话看了。。真是讽刺。。

为了看懂翻译你需要知道:欧拉函数,欧拉定理

下面是题解的翻译:

因为2333333不是素数,所以在2^(2^x) mod P 的时候会出现问题,不等于2^( 2^x mod P) mod P,那怎么办呢,题解第二行已给出公式A^x = A ^ (x%Phi(C) + Phi(C)) (mod C)。
证明可见:http://hi.baidu.com/aekdycoin/item/e493adc9a7c0870bad092fd9

这里最好打表解决,但是可以顺便学一下欧拉函数的实现
 1 #include<stdio.h>
 2 #include<string.h>
 3 int haha(int n)//求n的欧拉函数值
 4 {
 5     int res=n,i,j;
 6     for(i=2;i*i<=n;i++)
 7     {
 8         if(n%i==0)
 9         {
10             n=n/i;
11             while(n%i==0)
12                 n=n/i;
13             res=res/i*(i-1);
14         }
15         if(n<(i+1))
16             break;
17     }
18     if(n>1)
19         res=res/n*(n-1);
20     return res;
21 }
22 int main()
23 {
24     int T,n,m,i,sum;
25     while(scanf("%d",&T)!=EOF)
26     {
27         while(T--)
28         {
29           sum=0;
30           scanf("%d%d",&n,&m); 
31           for(i=1;i*i<=n;i++)
32               if(n%i==0)
33               {
34                   if(i>=m)
35                       sum=sum+haha(n/i);
36                   if((n/i)!=i&&(n/i)>=m)
37                       sum=sum+haha(i);
38               }
39           printf("%d\n",sum);
40         }
41     }
42     return 0;
43 }
欧拉函数
  1 #include <cstdio>
  2 #include <cstring>
  3 #include <vector>
  4 #include <algorithm>
  5 #include <ctime>
  6 #include <iostream>
  7 using namespace std;
  8 
  9 typedef __int64 ll;
 10 const int MOD = 2333333;
 11 const int N = 50000+5;
 12 
 13 int mo[20] = {2333333,2196720,580608,165888,55296,18432,
 14 6144,2048,1024,512,256,128,64,32,16,8,4,2,1};
 15 int pow2[33];
 16 
 17 vector<ll> vt[N];
 18 struct Segtree {
 19 #define lson rt<<1, l, mid
 20 #define rson rt<<1|1, mid+1, r
 21     ll mark[N<<2];
 22     int length[N<<2], sum[N<<2];
 23     void build(int rt, int l, int r) {
 24         mark[rt] = 0;
 25         length[rt] = r-l+1;
 26         if(l == r) {
 27             vt[l].clear();
 28             int x;
 29             scanf("%d", &x);
 30             vt[l].push_back(x);
 31             sum[rt] = x%MOD;
 32             return ;
 33         }
 34         int mid = l+r>>1;
 35         build(lson); build(rson);
 36         up(rt);
 37     }
 38 
 39     inline void Add(int &x, int y) {
 40         x += y;
 41         if(x >= MOD)    x -= MOD;
 42     }
 43 
 44     void up(int rt) {
 45         sum[rt] = sum[rt<<1] + sum[rt<<1|1];
 46         Add(sum[rt], 0);
 47     }
 48 
 49     void down(int rt) {
 50         if(mark[rt]) {
 51             mark[rt<<1] += mark[rt];
 52             mark[rt<<1|1] += mark[rt];
 53             Add(sum[rt<<1], 1LL*length[rt<<1]*mark[rt]%MOD);
 54             Add(sum[rt<<1|1], 1LL*length[rt<<1|1]*mark[rt]%MOD);
 55             mark[rt] = 0;
 56         }
 57     }
 58 
 59     void update(int rt, int l, int r, int L, int R, int v) {
 60         if(L <= l && R >= r) {
 61             mark[rt] += v;
 62             Add(sum[rt], 1LL*length[rt]*v%MOD);
 63             return ;
 64         }
 65         down(rt);
 66         int mid = l+r>>1;
 67         if(L <= mid)    update(lson, L, R, v);
 68         if(R > mid) update(rson, L, R, v);
 69         up(rt);
 70     }
 71 
 72     int pow_mod(int x, int n, int mod) {
 73         int ret = 1%mod;
 74         while(n) {
 75             if(n&1) ret = 1LL*ret*x%mod;
 76             x = 1LL*x*x%mod;
 77             n >>= 1;
 78         }
 79         return ret;
 80     }
 81 
 82     int cal(vector<ll> &v) {
 83         if(v.size() < 19) {
 84             int pos = v.size()-1;
 85             ll ret = v[0];
 86             bool flag = false;
 87             if(v[0] >= mo[pos]) {
 88                 flag = true;
 89                 ret = ret%mo[pos] + mo[pos];
 90             }
 91             pos--;
 92             for(int i = 1;i < v.size(); i++) {
 93                 if(flag) {
 94                     ret = (pow_mod(2, ret, mo[pos]) +v[i])%mo[pos] + mo[pos];
 95                 }
 96                 else {
 97                     if(ret >= 30) {
 98                         flag = true;
 99                         ret = (pow_mod(2, ret, mo[pos]) + v[i])%mo[pos]+mo[pos];
100                     }
101                     else if(pow2[ret] >= mo[pos]) {
102                         flag = true;
103                         ret = (pow_mod(2, ret, mo[pos]) + v[i])%mo[pos] + mo[pos];
104                     }
105                     else {
106                         ret = pow2[ret] + v[i];
107                         if(ret >= mo[pos]) {
108                             flag = true;
109                             ret = ret%mo[pos] + mo[pos];
110                         }
111                     }
112                 }
113                 pos--;
114             }
115             return ret%MOD;
116         }
117         else {
118             ll ret = 1;
119             int pos = 18;
120             bool flag = true;
121             for(int i = v.size()-18;i < v.size(); i++) {
122                 ret = (pow_mod(2, ret, mo[pos]) + v[i])%mo[pos] + mo[pos];
123                 pos--;
124             }
125             return ret%MOD;
126         }
127     }
128 
129     void modify(int rt, int l, int r, int x) {
130         if(l == r) {
131             if(mark[rt]) {
132                 vt[l][vt[l].size()-1] += mark[rt];
133                 mark[rt] = 0;
134             }
135             vt[l].push_back(0);
136             sum[rt] = cal(vt[l]);
137             return ;
138         }
139         down(rt);
140         int mid = l+r>>1;
141         if(x <= mid)    modify(lson, x);
142         else    modify(rson, x);
143         up(rt);
144     }
145 
146     int query(int rt, int l, int r, int L, int R) {
147         if(L <= l && R >= r)    return sum[rt];
148         down(rt);
149         int mid = l+r>>1, ret = 0;
150         if(L <= mid)    Add(ret, query(lson, L, R));
151         if(R > mid) Add(ret, query(rson, L, R));
152         up(rt);
153         return ret;
154     }
155 }tree;
156 
157 int n, m;
158 
159 void init() {
160     for(int i = 0;i <= 30; i++) pow2[i] = 1<<i;
161 }
162 
163 int main() {
164     init();
165     int op, l, r, x;
166     while(scanf("%d%d", &n, &m) == 2) {
167         tree.build(1, 1, n);
168         while(m--) {
169             scanf("%d", &op);
170             if(op == 1) {
171                 scanf("%d%d", &l, &r);
172                 printf("%d\n", tree.query(1, 1, n, l, r));
173             }
174             else if(op == 2) {
175                 scanf("%d", &x);
176                 tree.modify(1, 1, n, x);
177             }
178             else {
179                 scanf("%d%d%d", &l, &r, &x);
180                 tree.update(1, 1, n, l, r, x);
181             }
182         }
183     }
184     return 0;
185 }
代码君
 

转载于:https://www.cnblogs.com/usedrosee/p/4189664.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值