#include #include #include #include #include #include using namespace std; typedef long long LL; typedef vector VI; #define REP(i,n) for(int i=0, i##_len=(n); i inline void amin(T &x, const T &y) { if (y inline void amax(T &x, const T &y) { if (x void rprintf(const char *fmt, Iter begin, Iter end) { for (bool sp=0; begin!=end; ++begin) { if (sp) putchar(' '); else sp = true; printf(fmt, *begin); } putchar('\n'); } template struct ModInt { unsigned x; void undef() { x = (unsigned)-1; } bool isnan() const { return x == (unsigned)-1; } inline int getInt() const { return (int)x; } template T get() const { return (T)x; } inline int mod() const { return MOD; } ModInt(int y=0) { if (y<0 || MOD<=y) y %= MOD; if (y<0) y += MOD; x=y; } ModInt(long long y) { if (y<0 || MOD<=y) y %= MOD; if (y<0) y += MOD; x=y; } ModInt(unsigned long long y) { if (MOD<=y) x = y % (unsigned long long)MOD; else x = y; } ModInt &operator+=(const ModInt &y) { if ((x += y.x) >= MOD) x -= MOD; return *this; } ModInt &operator-=(const ModInt &y) { if ((x += MOD - y.x) >= MOD) x -= MOD; return *this; } ModInt &operator*=(const ModInt &y) { x = (unsigned long long)x * y.x % (unsigned long long)MOD; return *this; } ModInt &operator/=(const ModInt &y) { x = (unsigned long long)x * y.inv().x % (unsigned long long)MOD; return *this; } ModInt operator-() const { return (x ? MOD-x: 0); } ModInt inv() const { unsigned a = MOD, b = x; int u = 0, v = 1; while (b) { int t = a / b; a -= t * b; swap(a, b); u -= t * v; swap(u, v); } if (u < 0) u += MOD; return ModInt(u); } ModInt pow(long long y) const { ModInt b = *this, r = 1; if (y < 0) { b = b.inv(); y = -y; } for (; y; y>>=1) { if (y&1) r *= b; b *= b; } return r; } }; const LL MOD = 1000000007; typedef ModInt Mint; Mint operator+(Mint x, const Mint &y) { if ((x.x += y.x) >= (unsigned)x.mod()) x.x -= x.mod(); return x; } Mint operator-(Mint x, const Mint &y) { if ((x.x += x.mod() - y.x) >= (unsigned)x.mod()) x.x -= x.mod(); return x; } Mint operator*(Mint x, const Mint &y) { x.x = (unsigned long long)x.x * y.x % (unsigned long long)x.mod(); return x; } Mint operator/(Mint x, const Mint &y) { x.x = (unsigned long long)x.x * y.inv().x % (unsigned long long)x.mod(); return x; } bool operator<(const Mint &x, const Mint &y) { return x.x < y.x; } bool operator==(const Mint &x, const Mint &y) { return x.x == y.x; } bool operator!=(const Mint &x, const Mint &y) { return x.x != y.x; } struct Seg { int cnt[26]; Seg() { memset(cnt, 0, sizeof cnt); } Seg(char c) { memset(cnt, 0, sizeof cnt); cnt[c-'a'] = 1; } }; Seg operator+(const Seg &x, const Seg &y) { // do stuff something Seg z; REP (i, 26) z.cnt[i] = x.cnt[i] + y.cnt[i]; return z; }; const Seg unit = Seg(); struct Lazy { int add; Lazy() { add = 0; } Lazy(LL v_) : add(v_ % 26) {} Lazy& operator+=(const Lazy &y) { // do stuff something update(y.add); return *this; } void update(LL x) { // do stuff something (add += x) %= 26; } }; const Lazy lazy_unit = Lazy(); Seg operator*(const Lazy &x, const Seg &y) { // do stuff something Seg z; REP (i, 26) z.cnt[(i + x.add) % 26] = y.cnt[i]; return z; } struct SegmentTree { int n, m; vector d; vector lazy; SegmentTree(int n_=1) : n(n_) { if (n < 2) m = 1; else m = 2 << __lg(n-1); d.assign(m*2, unit); lazy.assign(m*2, lazy_unit); } template SegmentTree(const vector &a) : n(a.size()) { // When Seg(T) is defined if (n < 2) m = 1; else m = 2 << __lg(n-1); d.assign(m*2, unit); REP (i, n) d[i+m] = Seg(a[i]); for (int i=m; --i; ) d[i] = d[i*2] + d[i*2+1]; lazy.assign(m*2, lazy_unit); } inline void force(int k) { // if (k < m) { // lazy[k*2] += lazy[k]; // lazy[k*2+1] += lazy[k]; // } // // Lazy Update on d[k] // d[k] = lazy[k] * d[k]; // lazy[k] = lazy_unit; } inline Seg eval(int k) { return lazy[k] * d[k]; } void add(int x, int y, LL v) { add(x, y, v, 1, 0, m); } void add(int x, int y, LL v, int k, int l, int r) { force(k); if (r<=x || y<=l) return; if (x<=l && r<=y) { lazy[k].update(v); return; } add(x, y, v, k*2, l, (l+r)/2); add(x, y, v, k*2+1, (l+r)/2, r); d[k] = eval(k*2) + eval(k*2+1); } Seg query(int x, int y) { return query(x, y, 1, 0, m); } Seg query(int x, int y, int k, int l, int r) { force(k); if (r<=x || y<=l) return unit; if (x<=l && r<=y) return eval(k); return lazy[k] * (query(x, y, k*2, l, (l+r)/2) + query(x, y, k*2+1, (l+r)/2, r)); } }; int N, Q; char S[100111]; Mint pow2[100111]; int main() { scanf("%d%d", &N, &Q); scanf("%s", S); pow2[0] = 1; REP (i, 100011) pow2[i+1] = pow2[i] * 2; SegmentTree X(vector(S, S+N)); REP ($, Q) { char op[9]; int L, R, T; scanf("%s%d%d", op, &L, &R); R++; if (op[0] == '1') { scanf("%d", &T); T %= 26; X.add(L, R, T); } else { Seg z = X.query(L, R); Mint ans = 0; Mint fL[27], fR[27]; fL[0] = 1; fR[26] = 1; REP (i, 26) fL[i+1] = (z.cnt[i]? pow2[z.cnt[i]-1]: 1) * fL[i]; for (int i=26; i--; ) fR[i] = (z.cnt[i]? pow2[z.cnt[i]-1]: 1) * fR[i+1]; // all even ans += fR[0] - 1; // centre REP (i, 26) if (z.cnt[i]) ans += pow2[z.cnt[i]-1] * fL[i] * fR[i+1]; printf("%d\n", ans.getInt()); } } return 0; }