atcoder abc 353(A-E)

A.Buildings

有 N 个建筑物排成一行。左起第 𝑖i 栋建筑的高度为 Hi​ 。确定是否有比左侧第一个建筑物更高的建筑物。如果存在这样的建筑物,从左边找到最左边的建筑物的位置。

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main()
{
	int n;
	cin >> n;
	vector<int>h(n);
	int mn = -1,ans=-1;
	for (int i = 0;i < n;i++) {
		cin >> h[i];
		if (i == 0) {
			mn = h[i];
		}
		else {
			if (h[i] > mn&&ans==-1) {
				ans = i;
			}
		}
	}
	if (ans != -1)
		cout << ans + 1;
	else
		cout << -1;
	return 0;
}

B.AtCoder Amusement Park 

给定n个团队,依次进入容纳k的景区,如果当前剩余的位置仍够容纳新的a[i],继续进入,否则下一次再进入,确定次数。

思路:直接遍历,够就加上,不够就下一次

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	int n, k;
	cin >> n >> k;
	vector<int>a(n);
	for (int i = 0;i < n;i++) {
		cin >> a[i];
	}
	int ans = 0;
	int i = 0;
	while (i < n) {
		int s = a[i];
		int j = i+1;
		while (j < n && s+a[j] <= k) {
			s += a[j++];
		}
		ans++;
		i = j;
	}
	cout << ans;
	return 0;
}

C.Sigma Problem 

给定x,y,f(x,y)=(x+y)%1e8,n个整数求∑(N−1,​j)∑(N,i)​f(Ai​,Aj​).

思路:先排序,在顺序遍历,当前数为a[i],在i+1~n中二分找到a[i]+a[j]>=1e8的个数m,最后减去m*1e8,加上sum*(n-1),每个数被加了n-1次。

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long ll;
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	int mod = 1e8;
	ll n;
	cin >> n;
	vector<ll>a(n);
	ll sum = 0;
	for (int i = 0;i < n;i++) {
		cin >> a[i];
	}
	sort(a.begin(), a.end());
	ll num = 0;
	for (int i = 0;i < n;i++) {
		ll t = mod - a[i];
		int j = lower_bound(a.begin()+i, a.end(), t)-a.begin();
		if (j == i)++j;
		num += n-j;
		sum += a[i];
	}
	ll ans = sum * (n-1) - mod * num;
	cout << ans;
	return 0;
}

D.Another Sigma Problem

给定x,y,f(x,y)=xy(x,y串连起来),求∑(N−1,​j)∑(N,i)​f(Ai​,Aj​).

思路:前缀和,求出i~n的和,对于当前a[i]要乘多少,由i以后的数的位数决定,预处理i~n的数的位数之和,只需要a[i]*prod[i+1]即可求出a[i]与之后的数串联起来a[i]相应的值,再加上a[i]之后的数之和就可以了。

#include <iostream>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<algorithm>
#include<queue>
#include<functional>
#include<numeric>
#include<unordered_map>
using namespace std;
typedef long long ll;
ll get_bit(ll x) {
	ll s = 0;
	while (x) {
		x /= 10;
		s++;
	}
	return s;
}
ll Pow(ll x) {
	ll s = 1;
	ll t = get_bit(x);
	while (t) {
		s *= 10;
		t--;
	}
	return s;
}
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	int n;
	cin >> n;
	ll mod = 998244353;
	vector<ll>a(n + 1), suf(n + 1, 0),prod(n+1,0);
	for (int i = 1;i <= n;i++) {
		cin >> a[i];
		prod[i] = Pow(a[i]);
		a[i] %= mod;
	}
	suf[n] = a[n];
	for (int i = n - 1;i > 0;i--) {
		suf[i] = (suf[i + 1] + a[i]) % mod;
		prod[i] = (prod[i + 1] + prod[i]) % mod;
	}
	ll ans = 0;
	for (int i = 1;i < n;i++) {
		ans = (ans+a[i]*prod[i+1]) % mod;
		ans = (ans + suf[i + 1]) % mod;
	}
	cout << ans;
	return 0;
}

E.Yet Another Sigma Problem

给定字符串x,y,f(x,y)=x 和 𝑦 的最长公共前缀的长度,求∑(N−1,​j)∑(N,i)​f(Ai​,Aj​).

思路:用字典树来预处理,再遍历每个字符串,去掉当前字符串中字母在树中出现的次数,对于当前是否是最长公共前缀这个问题,我们每次求出当前前缀字符串和上一个前缀字符串出现的次数,差值即为最长公共前缀的个数,最后再处理最后一个位置即可。

#include<iostream>
#include<algorithm>
#include<unordered_map>
#include<vector>
using namespace std;
typedef long long ll;
const int N = 1e5 + 2;
struct Node {
	unordered_map<char, Node*>mp;
	ll cnt;
	Node() { cnt = 0; }
};
Node* root = new Node();
void build_tree(string& s) {
	Node* p = root;
	for (auto& c : s) {
		if (!p->mp.count(c)) {
			p->mp[c] = new Node();
		}
		p->mp[c]->cnt++;
		p = p->mp[c];
	}
}
void remove_node(string& s) {
	Node* p = root;
	for (auto& c : s) {
		p->mp[c]->cnt--;
		p = p->mp[c];
	}
}
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	int n;
	cin >> n;
	vector<string>a(n);
	for (int i = 0;i < n;i++) {
		cin >> a[i];
		build_tree(a[i]);
	}
	ll ans = 0;
	for (int i = 0;i < n-1;i++) {
		remove_node(a[i]);
		Node* p = root;
		if (a[i].size() == 1) {
			ans += p->mp[a[i][0]]->cnt;
			continue;
		}
		ll pre = p->mp[a[i][0]]->cnt, cur = 0;
		p = p->mp[a[i][0]];
		for (int j = 1;j < a[i].size();j++) {
			cur = p->mp[a[i][j]]->cnt;
			ans += (pre - cur)*j;
			pre = cur;
			p = p->mp[a[i][j]];
		}
		ans += pre * ll(a[i].size());
	}
	cout << ans;
	return 0;
}

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值