11/8训练笔记
P6273[eJOI2017] 魔法 题解
考虑定义\(S_{r_k} = \Sigma_{i = 1}^{r}[s_i = k]\),那么对于任意一个子串\([l,r]\),其为有魔法的子串的充要条件为\(S_{c_{r}} - S_{c_{l - 1}}\)对于任意的,在\(s\)中出现了的\(c\)为定值。
任取一个在\(s\)中出现了的字符\(A\),那么上述充要条件可转换为\(S_{c_{r}} - S_{c_{l - 1}} = S_{A_{r}} - S_{A_{l - 1}}\)对于\(s\)中出现的每个字符\(c\)都成立。
移项,得\(S_{c_{r}} - S_{A_{r}} = S_{c_{l - 1}} - S_{A_{l - 1}}\)
拿一个vector<int>
维护\({S_{c_{r}} - S_{A_{r}}|c \in S}\)即可
时间复杂度\(O(nklogn)\)
代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<set>
#include<map>
using namespace std;
int cnt1[100010],cnt[266],n,k,now,ans;
string s;
map<vector<int>,int> mp;
vector<int> v;
char a1[100010];
int main()
{
cin >> n >> s;
s = s;
strcpy(a1,s.c_str());
sort(a1,a1 + n);
mp[v = (vector<int>(k = unique(a1,a1 + n) - a1,0))] = 1;
for(int i = 0;i < n;i++) {
if(s[i] != a1[0]) {
v[lower_bound(a1,a1 + k,s[i]) - a1]++;
} else {
for(auto &j:v) {
j--;
}
v[0]++;
}
((ans += mp[v]++) %= (int)(1e9 + 7));
}
cout << ans << "\n";
}
P8579[CoE R5/Stoi2029] 半岛铁盒 题解
考虑最坏情况
即一个点是正无穷,剩下的都是0
然后每次分出来的气压肯定能少则少
随后注意到\(x\)显然可以二分。
那么考虑check
函数怎么写
注意到BFS即可,但是需要注意的是每次BFS可能会T
对于每个源点只进行一次BFS,BFS出dep数组,在check
时进行DP即可。
代码:
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#define int long long
using namespace std;
int dep[100010],vis[100010],n,m,p,q,u,v;
vector<int> E[100010];
queue<int> q1;
double d[100010],ans;
void Bfs(int now) {
for(int i = 1;i <= n;i++) {
dep[i] = 0;
vis[i] = 0;
}
q1.push(now);
dep[now] = 1;
vis[now] = 1;
while(!q1.empty()) {
int x = q1.front();
q1.pop();
for(auto i:E[x]) {
if(vis[i]) continue;
vis[i] = true;
dep[i] = dep[x] + 1;
q1.push(i);
}
}
}
bool check(double mid) {
double sum = 1.0 * (q - p) / q;
d[0] = 0;
d[1] = 1.0 * p / q;
for(int i = 1;i <= n;i++) {
if(!dep[i] || (dep[i] == 1)) continue;
d[dep[i]] = d[dep[i] - 1] / mid;
sum -= d[dep[i]];
}
return (sum >= 0.0);
}
signed main()
{
cin >> n >> m >> p >> q;
for(int i = 1;i <= m;i++) {
cin >> u >> v;
E[u].push_back(v);
E[v].push_back(u);
}
for(int i = 1;i <= n;i++) {
Bfs(i);
sort(dep + 1,dep + n + 1);
int cnt = 60;
double l = 1 - 0.00000001,r = 3e9 + 0.00000001;
while(cnt--) {
double mid = (l + r) / 2;
if(check(mid)) {
r = mid;
} else {
l = mid;
}
}
ans = max(ans,r);
}
printf("%.7lf",ans);
}