开始: 2023-04-30 00:00:00

230430稠州PK赛

结束: 2023-04-30 21:30:00
当前  2025-01-24 17:45:50  类型: IOI  状态: 已经结束 

出栈序列

方法二:贪心

分析一波:

栈内为空时选择入栈。

待入栈元素为空时选择出栈。

即可入栈也能出栈时,应如何选择呢?题意要求得到最小字典序,即下一个出栈字符越小越好。

栈顶元素小于等于待入栈元素最小值,则出栈。

栈顶元素大于待入栈元素最小值,入栈。

程序实现:

预处理出后缀最小值,栈不为空并且还有元素未入栈,比较栈顶元素与待入栈元素最小值决定入栈还是出栈。

时间复杂度: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;
}