#pragma comment(linker, "/STACK:64777216") #define _CRT_SECURE_NO_WARNINGS #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; #define FOR(i,a,b) for (int i = (a); i < (b); i++) #define RFOR(i,b,a) for (int i = (b) - 1; i >= (a); i--) #define ITER(it, a) for (__typeof(a.begin()) it = a.begin(); it != a.end(); it++) #define FILL(a, value) memset(a, value, sizeof(a)) #define SZ(a) (int)a.size() #define ALL(a) a.begin(), a.end() #define MP make_pair #define PB push_back typedef long long LL; typedef vector VI; typedef pair PII; const double PI = acos(-1.0); const int INF = 1000 * 1000 * 1000 + 7; const LL LINF = INF * (LL)INF; const int MOD = 1000 * 1000 * 1000 + 7; struct node { int y, val, cnt; int sum; int L, R; }; const int MAX = 100100; const int NUM = 26; node A[MAX * NUM]; int cnt; int getCnt(int ind) { if (ind == -1) return 0; return A[ind].cnt; } int getSum(int ind) { if (ind == -1) return 0; return A[ind].sum; } void updCnt(int ind) { if (ind == -1) return; A[ind].cnt = getCnt(A[ind].L) + getCnt(A[ind].R) + 1; A[ind].sum = getSum(A[ind].L) + getSum(A[ind].R) + A[ind].val; } pair split(int ind, int cnt) { if (ind == -1) return MP(-1, -1); if (cnt == 0) return MP(-1, ind); if (cnt == getCnt(ind)) return MP(ind, -1); int left = getCnt(A[ind].L); pair res; if (left >= cnt) { res = split(A[ind].L, cnt); A[ind].L = res.second; res.second = ind; } else { res = split(A[ind].R, cnt - left - 1); A[ind].R = res.first; res.first = ind; } updCnt(ind); return res; } int merge(int a, int b) { if (a == -1) return b; if (b == -1) return a; int res; if (A[a].y > A[b].y) { int x = merge(A[a].R, b); A[a].R = x; res = a; } else { int x = merge(a, A[b].L); A[b].L = x; res = b; } updCnt(res); return res; } set Y; int PB(int root, int val) { int y; do { y = rand() * rand(); } while (Y.count(y) != 0); Y.insert(y); A[cnt].y = y; A[cnt].L = A[cnt].R = -1; A[cnt].val = val; A[cnt].sum = val; A[cnt].cnt = 1; root = merge(root, cnt); cnt++; return root; } char S[MAX]; int RTS[NUM]; int TR[NUM][3]; void doSplit(int L, int R) { FOR(j, 0, NUM) { pair a = split(RTS[j], L); TR[j][0] = a.first; a = split(a.second, R - L + 1); TR[j][1] = a.first; TR[j][2] = a.second; } } void doMerge() { FOR(j, 0, NUM) { RTS[j] = merge(TR[j][0], merge(TR[j][1], TR[j][2])); } } LL bpow(LL a, LL b) { LL res = 1; while (b) { if (b & 1) res = (res * a) % MOD; a = (a * a) % MOD; b /= 2; } return res; } LL inv(LL a) { return bpow(a, MOD - 2); } LL PW[MAX]; LL PWINV[MAX]; LL getNum(int n) { if (n == 0) return 1; return PW[n - 1]; } LL getNumInv(int n) { if (n == 0) return 1; return PWINV[n - 1]; } int main() { //freopen("in.txt", "r", stdin); //ios::sync_with_stdio(false); cin.tie(false); PW[0] = 1; PWINV[0] = 1; FOR(i, 1, MAX) { PW[i] = PW[i - 1] * 2; if (PW[i] >= MOD) PW[i] -= MOD; PWINV[i] = inv(PW[i]); } int n, m; scanf("%d%d", &n, &m); scanf("%s", S); FILL(RTS, -1); FOR(i, 0, n) { FOR(j, 0, NUM) { if (S[i] - 'a' == j) RTS[j] = PB(RTS[j], 1); else RTS[j] = PB(RTS[j], 0); } } FOR(i, 0, m) { int t; scanf("%d", &t); if (t == 1) { int L, R, N; scanf("%d%d%d", &L, &R, &N); doSplit(L, R); FOR(j, 0, NUM) { RTS[(j + N) % NUM] = TR[j][1]; } FOR(j, 0, NUM) { TR[j][1] = RTS[j]; } doMerge(); } else { int L, R; scanf("%d%d", &L, &R); doSplit(L, R); LL mul = 1; /* FOR(i, 0, NUM) { cout << getSum(TR[i][1]) << ' '; } cout << endl;*/ FOR(i, 0, NUM) { int c = getSum(TR[i][1]); mul = (mul * getNum(c)) % MOD; } // cout << mul << endl; LL res = mul; FOR(i, 0, NUM) { int c = getSum(TR[i][1]); if (c == 0) continue; LL cur = (mul * getNumInv(c)) % MOD; c = getSum(TR[i][1]); cur = (cur * getNum(c)) % MOD; res = (res + cur) % MOD; } res--; if (res < 0) res += MOD; cout <