結果
| 問題 |
No.1845 Long Substrings
|
| コンテスト | |
| ユーザー |
srjywrdnprkt
|
| 提出日時 | 2025-03-29 04:33:08 |
| 言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 245 ms / 2,000 ms |
| コード長 | 1,892 bytes |
| コンパイル時間 | 3,752 ms |
| コンパイル使用メモリ | 285,940 KB |
| 実行使用メモリ | 16,248 KB |
| 最終ジャッジ日時 | 2025-03-29 04:33:18 |
| 合計ジャッジ時間 | 9,192 ms |
|
ジャッジサーバーID (参考情報) |
judge1 / judge2 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | AC * 34 |
ソースコード
#include <bits/stdc++.h>
#include <atcoder/modint>
using namespace std;
using namespace atcoder;
using ll = long long;
using mint = modint1000000007;
int main(){
cin.tie(nullptr);
ios_base::sync_with_stdio(false);
/*
部分列DP
dp(i) = i文字目まででの部分文字列の種類数
c=a,...,zのi以降の最小のインデックスp_cに
dp(p_c) += dp(i)
dp(i) = i文字目の塊まででの部分文字列の種類数
異なる文字(S_i != S_j) -> jのどこで止めるか?
dp(j) += dp(i) * A_j
同じ文字列(S_i == S_j) -> 重複を避けるために、A_iの末尾からの遷移しか許可しない。
iiooii
A_1までi, ii (2)
A_3までi+i, i+ii, ii+i, ii+ii (3)
dp(i, j) = i文字目の塊までで、i文字目の塊を全て使った(j=1)か使ってない(j=0)ときの部分文字列の数
*/
int N;
cin >> N;
vector<int> A(N+1);
for (int i=1; i<=N; i++) cin >> A[i];
string S;
cin >> S;
S = '$' + S;
char c;
vector<vector<int>> v(26);
for (int i=1; i<=N; i++){
c = S[i];
v[c-'a'].push_back(i);
}
mint ans=0;
vector dp(N+1, vector<mint>(2));
dp[0][0] = 1;
for (int i=0; i<=N; i++){
c = S[i];
for (int j=0; j<26; j++){
auto it = lower_bound(v[j].begin(), v[j].end(), i+1);
if (it != v[j].end()){
if (c-'a' == j){
dp[*it][1] += dp[i][1];
dp[*it][0] += dp[i][1] * (A[*it]-1);
}
else{
dp[*it][1] += dp[i][1] + dp[i][0];
dp[*it][0] += (dp[i][1] + dp[i][0]) * (A[*it]-1);
}
}
}
}
for (int i=1; i<=N; i++) ans += dp[i][0] + dp[i][1];
cout << ans.val() << endl;
return 0;
}
srjywrdnprkt