G. Link with Monotonic Subsequence
总结:
- 子串(substring):s.substring,连续的
- 子序列(subsequence):不连续的
- 从二元组至少为一半可得sqrt(n)
由于最多两个变量,而要让整个最小必定是均匀分布的,考虑1/2或sqrt(),由数字举例得应用sqrt()
#include<bits/stdc++.h>
using namespace std;
int main() {
int t;
cin >> t;
while(t--){
int n;
cin >> n;
int m = ceil(sqrt(n));
int now = m;
int pre = 0;
while(pre <= n){
for (int i = now; i > pre; --i){
cout << i << " ";
}
now = min(now + m, n);
pre = min(pre + m, n + 1);
}
cout << endl;
}
return 0;
}
K. Link with Bracket Sequence I
总结:
- 明显dp,变量为是否加入括号,所以应该选择一个括号为重点,对状态进行分析
- 两个字串的匹配需要两维,是否合法还需要一维
dp[i][j][k] : 前i个里匹配了j个序列,多出了k个左括号(不合法)
当前为左括号:
- 匹配长度不变 : dp[i - 1][j][k + 1] 不合法的左括号减少,这一位不管
- 匹配长度增加 :dp[i - 1][j - 1][k - 1] 不合法的左括号增加,这一位为左括号
右括号同理,与左括号刚好相反
int dp[205][205][205];
int main() {
IOS;
int t;
cin >> t;
while(t--){
re(dp);
int n, m;
cin >> n >> m;
string s;
cin >> s;
s = " " + s;
dp[0][0][0] = 1;
for (int i = 1; i <= m; ++i){
for (int j = 0; j <= i; ++j){
for (int k = 0; k <= i; ++k){
if(j == 0){
if(k)
dp[i][0][k] += dp[i - 1][0][k - 1];
dp[i][0][k] += dp[i - 1][0][k + 1];
}
else if(s[j] == '('){
dp[i][j][k] += dp[i - 1][j][k + 1];
if(k)
dp[i][j][k] += dp[i - 1][j - 1][k - 1];
}
else {
if(k)
dp[i][j][k] += dp[i - 1][j][k - 1];
dp[i][j][k] += dp[i - 1][j - 1][k + 1];
}
dp[i][j][k]%=mod;
}
}
}
cout << dp[m][n][0] << endl;
}
return 0;
}
D. Link with Game Glitch
总结:
- 拓扑排序:判断是否有环(不管正负), bf:判断负环
- 无限循环可以考虑下是不是图
- spfa并不是完全没用的,例如这道题判负环
vector<PII> e[2010];
double dis[2010];
const int inf = 0x3f3f3f3f;
int cnt[2010];
bool vis[2010];
bool check(int n, double mid) {
mid = log(mid);
memset(dis, 0, sizeof(dis));
re(cnt);
queue<int> q;
for(int i = 1; i <= n; ++i){
q.push(i);
vis[i] = true;
}
while(!q.empty()){
int temp = q.front();
q.pop();
vis[temp] = false;//反复出队入队
for(auto w: e[temp]){
if(dis[w.first] < dis[temp] + mid + w.second){
dis[w.first] = dis[temp] + mid + w.second;
cnt[w.first] = cnt[temp] + 1;
if(cnt[w.first] > n)//有负环
return false;
if(!vis[w.first]){
q.push(w.first);
vis[w.first] = true;
}
}
}
}
return true;
}
int main() {
int n, m;
cin >> n >> m;
int start = 0;
for(int i = 0; i < m; ++i){
int b, d;
double a, c;
cin >> a >> b >> c >> d;
e[b].push_back({d, log(c / a)});
}
double l = 0, r = 1000;
while((r - l) >= 1e-6){
double mid = (l + r) / 2;
if(check(n,mid))
l = mid;
else
r = mid;
}
cout << l;
return 0;
}