出栈序列
方法二:贪心
分析一波:
栈内为空时选择入栈。
待入栈元素为空时选择出栈。
即可入栈也能出栈时,应如何选择呢?题意要求得到最小字典序,即下一个出栈字符越小越好。
栈顶元素小于等于待入栈元素最小值,则出栈。
栈顶元素大于待入栈元素最小值,入栈。
程序实现:
预处理出后缀最小值,栈不为空并且还有元素未入栈,比较栈顶元素与待入栈元素最小值决定入栈还是出栈。
时间复杂度:O(n)
#include <bits/stdc++.h> using namespace std; const int MAXN = 1E5 + 10; string s; int n; char a[MAXN]; int main(){ cin >> n >> s; //预处理出后缀最小值 a[n - 1] = s[n - 1]; for (int i = n - 2; i >= 0; --i) a[i] = min(s[i], a[i + 1]); //模拟贪心求解 stack<char>stk; stk.push(s[0]); int inc = 1;//指向下一个入栈字符 while (!stk.empty() || inc < n){ if (stk.empty() || inc < n && stk.top() > a[inc]){ stk.push(s[inc++]); } else{ cout << stk.top(); stk.pop(); } } cout << endl; return 0; }
数对统计
如果直接暴力枚举,那么会T
这里考虑策略
不重复的数对数量
只要每个最后的数乘前面出现的不同数的数量就行了(包括前面的他自己)
再求个和
#include <bits/stdc++.h> using namespace std; int n,a[100010];long long c,ans;int v[100010];bool v2[100010]; int main(){ cin >> n; for(int i = 1;i <= n;i++) cin >> a[i]; for(int i = n;i > 0;i--){ if(!v[a[i]]) v[a[i]] = i; } for(int i = 1;i <= n;i++){ if(v[a[i]] == i) ans += c; if(!v2[a[i]]) v2[a[i]] = 1,c++; } cout << ans; return 0; }
加与乘
对于每个+ 和 * 进行维护 , 统计每次加上需要进行的*次数
#include<bits/stdc++.h> using namespace std; #define MAXN 200010 #define ll long long const int d=1e9+7; int n,q,a[MAXN],b[MAXN]; char op[MAXN]; ll ans[MAXN],g=1;//当前已经被乘上多少了 int main(){ cin>>n>>q; for(int i=1;i<=q;++i){ cin>>op[i]; if(op[i]=='+') cin>>a[i]>>b[i]; else cin>>b[i]; }for(int i=q;i>=1;--i){ if(op[i]=='+') ans[a[i]]=(ans[a[i]]+b[i]*g%d)%d;//加法运算,去掉取模即为(ans[a[i]]+b[i]*g),ans为被运算的数组 else g=g*b[i]%d;//乘法对g操作 }for(int i=1;i<=n;++i) cout<<ans[i]<<" "; cout<<endl; return 0; }
点菜
树形背包的原题了。
#include <bits/stdc++.h> using namespace std; inline int read() { int x(0), f(1); char c = getchar(); while (c < '0' || c > '9') f = c == '-' ? -1 : 1, c = getchar(); while (c <= '9' && c >= '0') x = x * 10 + c - 48, c = getchar(); return x * f; } const int N = 50010; int n, W, w[N], v[N]; vector<int>G[N]; void add(int x, int y) { G[x].push_back(y); } vector<vector<int>>f; //int f[5000][5000]; void dfs(int x, int dep) { for (auto y : G[x]) { for (int j = dep + w[y]; j <= W; j++) f[y][j] = f[x][j - w[y]] + v[y]; //转移向子树 y dfs(y, dep + w[y]); for (int j = dep + w[y]; j <= W; j++) f[x][j] = max(f[x][j], f[y][j]); //合并子树 y } } int main() { n = read(), W = read(); f.resize(n + 1); for (int i = 0; i <= n; i++) f[i].resize(W + 1); for (int i = 1; i <= n; i++) add(read(), i); for (int i = 1; i <= n; i++) w[i] = read(); for (int i = 1; i <= n; i++) v[i] = read(); dfs(0, 0); printf("%d", f[0][W]); return 0; }