[zoj3813]Alternating Sum 公式化简,线段树
题意:给一个长度不超过100000的原串S(只包含数字0-9),令T为将S重复若干次首尾连接后得到的新串,有两种操作:(1)修改原串S某个位置的值(2)给定L,R,询问T中L<=i<=j<=R的G(i,j)的和,G(i,j)=Ti-Ti+1+Ti+2-Ti+3+...+(-1)j-iTj,L,R小于1e18
思路:从公式看不出用什么方法快速计算,不妨先对公式化简。令f(i)=(j:i->R)ΣG(i,j),则有:f(i)=G(i,i)+G(i,i+1)+...+G(i,R) (a)
将 (a)的每一项展开,不难得到:f(i)=(R-i+1)*Ti - (R-i)*Ti+1 + (R-i-1)*Ti+3 +... + (-1)R-i*TR
然后将f(i)求和,sum(L,R)=(i:L->R)Σf(i) = f(L) + f(L+1) + f(L+2) + ... + f(R),将每一项展开得到:
f(L)= (R-L+1)*TL - (R-L)*TL+1 + (R-L-1)*TL+2 + ... + (-1)R-L*TR
f(L+1)= (R-L)*TL+1 - (R-L-1)*TL+2 - ... + (-1)R-L-1*TR
.
.
.
f(R-1)= 2TR-1 - TR
f(R)= TR
于是 sum(L,R)=(R-L+1)*TL + (R-L-1)*TL+2 + ... + 2TR-1 ,当R-L+1为偶数时
(R-L+1)*TL + (R-L-1)*TL+2 + ... + TR ,当R-L+1为奇数时
由于有修改操作,而sum(L,R) 可以比较容易的通过区间来合并,只需在线段树的每个区间[L,R]上记录四个值,var1表示从sum(L,R),var2表示sum(L+1,R),con1=TL + TL+2 + ... ,con2=TL+1 + TL+3 + ...,con1和con2在合并区间时需要用到,而左子区间长度为奇数会导致合并区间时右子区间需要从第二个数开始的sum值,所以需要记录sum(L+1,R)和con2。具体操作见代码。
到这里,问题并没解决,题目给的L,R太大,不过由于是重复原串S得到的串,肯定有快速计算重复部分的答案。对询问的区间左右边界定位,看是处在第几个S串里面,如果在同一个里面,直接算区间就行,如果跨多个S串,则答案由前缀、重复串、后缀这三部分组成,而重复串的值可以用快速幂的方法用logn次合并得到,每次合并都是O(1)的,三部分的值都出来后对这三部分进行合并即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 | #include <map> #include <set> #include <cmath> #include <ctime> #include <deque> #include <queue> #include <stack> #include <vector> #include <cstdio> #include <string> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define X first #define Y second #define pb push_back #define mp make_pair #define all(a) (a).begin(), (a).end() #define fillchar(a, x) memset(a, x, sizeof(a)) typedef long long ll; typedef pair< int , int > pii; typedef unsigned long long ull; #ifndef ONLINE_JUDGE void RI(vector< int >&a, int n){a.resize(n); for ( int i=0;i<n;i++) scanf ( "%d" ,&a[i]);} void RI(){} void RI( int &X){ scanf ( "%d" ,&X);} template < typename ...R> void RI( int &f,R&...r){RI(f);RI(r...);} void RI( int *p, int *q){ int d=p<q?1:-1; while (p!=q){ scanf ( "%d" ,p);p+=d;}} void print(){cout<<endl;} template < typename T> void print( const T t){cout<<t<<endl;} template < typename F, typename ...R> void print( const F f, const R...r){cout<<f<< ", " ;print(r...);} template < typename T> void print(T*p, T*q){ int d=p<q?1:-1; while (p!=q){cout<<*p<< ", " ;p+=d;}cout<<endl;} #endif template < typename T> bool umax(T&a, const T&b){ return b<=a? false :(a=b, true );} template < typename T> bool umin(T&a, const T&b){ return b>=a? false :(a=b, true );} template < typename T> void V2A(T a[], const vector<T>&b){ for ( int i=0;i<b.size();i++)a[i]=b[i];} template < typename T> void A2V(vector<T>&a, const T b[]){ for ( int i=0;i<a.size();i++)a[i]=b[i];} const double PI = acos (-1.0); const int INF = 1e9 + 7; /* -------------------------------------------------------------------------------- */ template < int mod> struct ModInt { const static int MD = mod; int x; ModInt(ll x = 0): x(x % MD) {} int get() { return x; } ModInt operator + ( const ModInt &that) const { int x0 = x + that.x; return ModInt(x0 < MD? x0 : x0 - MD); } ModInt operator - ( const ModInt &that) const { int x0 = x - that.x; return ModInt(x0 < MD? x0 + MD : x0); } ModInt operator * ( const ModInt &that) const { return ModInt(( long long )x * that.x % MD); } ModInt operator / ( const ModInt &that) const { return * this * that.inverse(); } ModInt operator += ( const ModInt &that) { x += that.x; if (x >= MD) x -= MD; } ModInt operator -= ( const ModInt &that) { x -= that.x; if (x < 0) x += MD; } ModInt operator *= ( const ModInt &that) { x = ( long long )x * that.x % MD; } ModInt operator /= ( const ModInt &that) { * this = * this / that; } ModInt inverse() const { int a = x, b = MD, u = 1, v = 0; while (b) { int t = a / b; a -= t * b; std::swap(a, b); u -= t * v; std::swap(u, v); } if (u < 0) u += MD; return u; } }; typedef ModInt<1000000007> mint; const int maxn = 1e5 + 7; const int md = 1e9 + 7; int a[maxn]; class SegTree { #define lson l, m, rt << 1 #define rson m + 1, r, rt << 1 | 1 struct Node { mint var1, var2, con1, con2; }; Node tree[maxn << 2]; int n; Node &merge( const Node &ul, const ll &Llen, const Node &ur, const ll &Rlen) { static Node ans; if (Llen & 1) { ans.var1 = ul.var1 + ur.var2 + ul.con1 * Rlen; ans.var2 = ul.var2 + ur.var1 + ul.con2 * Rlen; ans.con1 = ul.con1 + ur.con2; ans.con2 = ul.con2 + ur.con1; } else { ans.var1 = ul.var1 + ur.var1 + ul.con1 * Rlen; ans.var2 = ul.var2 + ur.var2 + ul.con2 * Rlen; ans.con1 = ul.con1 + ur.con1; ans.con2 = ul.con2 + ur.con2; } return ans; } void build( int l, int r, int rt) { if (l == r) { Node &u = tree[rt]; u.var1 = u.con1 = a[l]; u.var2 = u.con2 = 0; return ; } int m = (l + r) >> 1; build(lson); build(rson); int len = r - l + 1; tree[rt] = merge(tree[rt << 1], m - l + 1, tree[rt << 1 | 1], r - m); } void update( int p, int x, int l, int r, int rt) { if (l == r) { Node &u = tree[rt]; u.var1 = u.con1 = x; u.var2 = u.con2 = 0; return ; } int m = (l + r) >> 1; if (p <= m) update(p, x, lson); else update(p, x, rson); tree[rt] = merge(tree[rt << 1], m - l + 1, tree[rt << 1 | 1], r - m); } Node query( int L, int R, int l, int r, int rt) { if (L <= l && r <= R) return tree[rt]; int m = (l + r) >> 1; if (R <= m) return query(L, R, lson); if (L > m) return query(L, R, rson); Node ul = query(L, m, lson), ur = query(m + 1, R, rson); return merge(ul, m - L + 1, ur, R - m); } Node get(ll cnt) { if (cnt == 1) return tree[1]; Node u = get(cnt >> 1); ll c = cnt >> 1; u = merge(u, c * n, u, c * n); if (cnt & 1) u = merge(u, c * n * 2, tree[1], n); return u; } public : void build( int n) { this ->n = n; build(1, n, 1); } void update( int p, int x) { update(p, x, 1, n, 1); } mint query(ll L, ll R) { ll lid = (L - 1) / n + 1, rid = (R - 1) / n + 1, dif = rid - lid; L = (L - 1) % n + 1; R = (R - 1) % n + 1; if (dif == 0) return query(L, R, 1, n, 1).var1; Node ul = query(L, n, 1, n, 1), ur = query(1, R, 1, n, 1); int Llen = n - L + 1, Rlen = R; mint var = ul.var1 + ul.con1 * ((dif - 1) * n + Rlen); if (dif - 1) { Node buf = get(dif - 1); if (Llen & 1) var += buf.var2 + buf.con2 * Rlen; else var += buf.var1 + buf.con1 * Rlen; } if ((Llen + (dif - 1) * n) & 1) var += ur.var2; else var += ur.var1; return var; } }; SegTree st; char s[maxn]; int main() { #ifndef ONLINE_JUDGE freopen ( "in.txt" , "r" , stdin); //freopen("out.txt", "w", stdout); #endif // ONLINE_JUDGE int T, n, m, t; ll x, y; cin >> T; while (T --) { scanf ( "%*c%s" , s); int n = strlen (s); for ( int i = 0; i < n; i ++) { a[i + 1] = s[i] - '0' ; } st.build(n); cin >> m; while (m --) { scanf ( "%d%lld%lld" , &t, &x, &y); if (t == 1) st.update(x, y); else printf ( "%d\n" , st.query(x, y).get()); } } return 0; } |