2023-09-20-CSP-S-2023-复赛
考场上 T1, T3 做出来了
T2, T4 CF 上有原题
这里就记录一下 T2 正解
令
那么
nxt[i] := i+1
while a[nxt[i]] != a[i]:
nxt[i] = nxt[nxt[i]] + 1
但是这么做是
所以引入
那么就有这样的关系
若
当
当
原题的代码:(CCF版缩小了值域
#include <bits/stdc++.h>
using namespace std;
const int N = 3e5 + 10;
int nQ;
int n;
int a[N];
int dp[N];
map<int, int> nxta[N];
void input() {
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
}
void solve() {
for (int i = n + 1; i >= 1; i--) {
nxta[i].clear();
dp[i] = 0;
}
for (int i = n - 1; i >= 1; i--) {
int nxt;
if (a[i] == a[i + 1]) {
nxt = i + 1;
nxta[i] = move(nxta[nxt + 1]);
if (nxt + 1 <= n) nxta[i][a[nxt + 1]] = nxt;
dp[i] = dp[nxt + 1] + 1;
} else {
nxt = nxta[i + 1][a[i]] + 1;
if (nxt != 1) {
nxta[i] = move(nxta[nxt + 1]);
if(nxt + 1 <= n) nxta[i][a[nxt + 1]] = nxt; //***
dp[i] = dp[nxt + 1] + 1;
}
}
}
long long ans = 0; //***
for (int i = 1; i < n; i++) {
ans += dp[i];
}
cout << ans << endl;
}
int main() {
scanf("%d", &nQ);
for (int iQ = 1; iQ <= nQ; iQ++) {
input();
solve();
}
return 0;
}
考虑一个栈 S,每次加入一个序列中的元素,如果该元素和栈顶的是相同的,那么就消掉
令
如果有
接下来状态压缩,令
给
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n;
string s;
string stk;
const ll b1=131,b2=151;
const ll mod=1e9+7;
ll p1[2000010];
ll p2[2000010];
ll h1,h2;
map<pair<ll,ll>,int> st;
ll ans;
int main(){
cin>>n>>s;
p1[0]=p2[0]=1;
for(int i=1;i<=n;i++){
p1[i]=p1[i-1]*b1%mod;
p2[i]=p2[i-1]*b2%mod;
}
stk='-';
h1=(int)stk[0]*p1[0]%mod;
h2=(int)stk[0]*p2[0]%mod;
st[make_pair(h1,h2)]++;
for(char c:s){
if(c==stk.back()){
h1-=(int)stk.back()*p1[stk.size()-1]%mod;
h1+=mod;
h1%=mod;
h2-=(int)stk.back()*p2[stk.size()-1]%mod;
h2+=mod;
h2%=mod;
stk.pop_back();
}else{
h1+=(int)c*p1[stk.size()]%mod;
h1%=mod;
h2+=(int)c*p2[stk.size()]%mod;
h2%=mod;
stk.push_back(c);
}
ans+=st[make_pair(h1,h2)];
st[make_pair(h1,h2)]++;
}
cout<<ans<<endl;
return 0;
}