训练赛
Posted bozhao
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了训练赛相关的知识,希望对你有一定的参考价值。
CCSU团队训练赛
H - Billionaires URAL - 1650
? You probably are aware that Moscow holds the first place in the world with respect to the number of billionaires living there. However, the work of billionaires is such that they have to travel a lot. That is why some other city can be the first in such a list on certain days. Your friends from FSB, FBI, MI5, and Shin Bet have provided you with information about movements of billionaires during some period of time. Your employer asks you to determine for each city the number of days during this period on which this city exceeded all other cities in the total amount of money that billionaires staying in this city have.
Input
? In the first line you are given the number n of billionaires (1 ≤ n ≤ 10000) . The following n lines contain information about these people: their names, cities where they were staying at the beginning of the period, and their fortunes. In the next line you are given the number m of days in the period for which you have the information (1 ≤ m ≤ 50000) and the number k of travels of the billionaires (0 ≤ k ≤ 50000) . The following k lines contain the list of travels in the following format: the number of the day (from 1 to m?1), the name of the person, and the city of destination. You may assume that billionaires depart late at night and arrive to the destination city on the next day‘s morning. They cannot make more than one travel each day. The numbers of days in the list are not decreasing. All names of people and cities consist of at most 20 English letters; you must take into consideration the case of the symbols. The fortunes are in the range from 1 to 100 billions (one billion is a thousand million).
Output
? In each line of the output give the name of a city and, after a space, the number of days during which this city was the first with respect to the sum of fortunes of the billionaires staying there. Leave out those cities for which there were no such days. The cities must be sorted alphabetically (with the usual symbol order: ABC...Zabc...z).
Example
input | output |
---|---|
5 Abramovich London 15000000000 Deripaska Moscow 10000000000 Potanin Moscow 5000000000 Berezovsky London 2500000000 Khodorkovsky Chita 1000000000 25 9 1 Abramovich Anadyr 5 Potanin Courchevel 10 Abramovich Moscow 11 Abramovich London 11 Deripaska StPetersburg 15 Potanin Norilsk 20 Berezovsky Tbilisi 21 Potanin StPetersburg 22 Berezovsky London |
Anadyr 5 London 14 Moscow 1 |
题解:恶心的题线段树模拟记住是先算贡献再更新
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 7;
struct segement{
ll maxn, maxn1;
int pos;
}tree[4 * N];
ll a[N];
#define lson 2 * node
#define rson 2 * node + 1
#define m (l + r) / 2
struct data{
string na, ad;
};
void build(int l, int r, int node){
if(l == r){
tree[node].maxn = a[l];
tree[node].maxn1 = 0;
tree[node].pos = l;
return;
}
build(l, m, lson);
build(m + 1, r, rson);
if(tree[rson].maxn > tree[lson].maxn){
tree[node].maxn = tree[rson].maxn;
tree[node].pos = tree[rson].pos;
if(tree[rson].maxn1 > tree[lson].maxn){
tree[node].maxn1 = tree[rson].maxn1;
}else{
tree[node].maxn1 = tree[lson].maxn;
}
}else{
tree[node].maxn = tree[lson].maxn;
tree[node].pos = tree[lson].pos;
if(tree[lson].maxn1 > tree[rson].maxn){
tree[node].maxn1 = tree[lson].maxn1;
}else{
tree[node].maxn1 = tree[rson].maxn;
}
}
}
void update(ll v, int pos, int l, int r, int node){
if(l == r){
tree[node].maxn += v;
return;
}
if(pos <= m) update(v, pos, l, m, lson);
else update(v, pos, m + 1, r, rson);
if(tree[rson].maxn > tree[lson].maxn){
tree[node].pos = tree[rson].pos;
tree[node].maxn = tree[rson].maxn;
if(tree[rson].maxn1 > tree[lson].maxn){
tree[node].maxn1 = tree[rson].maxn1;
}else{
tree[node].maxn1 = tree[lson].maxn;
}
}else{
tree[node].maxn = tree[lson].maxn;
tree[node].pos = tree[lson].pos;
if(tree[lson].maxn1 > tree[rson].maxn){
tree[node].maxn1 = tree[lson].maxn1;
}else{
tree[node].maxn1 = tree[rson].maxn;
}
}
}
vector<data> g[N];
map<string , string> name;
map<string, int> address;
map<string, ll>money;
map<string, int>ans;
string cnt[N];
int main(){
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int n, day, q;
cin >> n;
int top = 1;
for(int i = 1; i <= n; i++){
string na, ad;
ll w;
cin >> na >> ad >> w;
money[na] = w;
name[na] = ad;
if(address[ad]){
a[address[ad]] += w;
}else{
a[top] = w;
cnt[top] = ad;
address[ad] = top++;
}
}
int maxn = 100000;
build(1, maxn, 1);
cin >> day >>q;
while(q--){
int d;
string ad, na;
cin >> d>> na>> ad;
g[d].push_back({na, ad});
}
for(int i = 1; i <= day; i++){
if(tree[1].maxn1 != tree[1].maxn){
ans[cnt[tree[1].pos]]++;
}
for(int j = 0; j < g[i].size(); j++){
string na = g[i][j].na;
string ad = g[i][j].ad;
string last_ad = name[na];
name[na] = ad;
int pos = address[last_ad];
ll va = money[na];
update(-va, pos, 1, maxn, 1);
if(address[ad] == 0){
cnt[top] = ad;
address[ad] = top++;
}
pos = address[ad];
va = money[na];
update(va, pos, 1, maxn, 1);
}
}
for(auto it: ans){
cout <<it.first <<" " << it.second << endl;
}
}
/*
5
Abramovich London 10000000000
Deripaska Moscow 10000000000
Potanin Moscow 5000000000
Berezovsky London 2500000000
Khodorkovsky Chita 1000000000
25 9
1 Abramovich Anadyr
5 Potanin Courchevel
10 Abramovich Moscow
11 Abramovich London
11 Deripaska StPetersburg
15 Potanin Norilsk
20 Berezovsky Tbilisi
21 Potanin StPetersburg
22 Berezovsky London
*/
G - Sum of Digits URAL - 1658
题意: 给你s1, s2分别表示 一个数每个数字之和等于s1 每个数字之间数字的平方和等于s2
求一个最小的这样的数字。如果没用输出 No solution 如果这个数字的长度大于100输出
No solution
题解:
设 (dp[i][j]) 表示每个数字之和为i, 每个数字平方和为j能得到的最小长度。
初始化时 把(dp)数组赋值为无穷大,(dp[0][0] = 0)
那么(dp[i][j]) = (min(dp[i][j], dp[i - k][i - k *k ])) 其中k为 1到9
知道每种状态最优的最小长度,怎么才能求出答案呢?
我们可以贪心。
(if(dp[s1 - k][s2 - k * k] + 1 == dp[s1][s2])) 其中k 是从1 到 9 开始贪心
如果这个条件成立, 那么 第1位数就可以选 k, 然后 s1 = s1 - k, s2 = s2 - k *k
一直贪最小的最后得到一个最优解
#include<bits/stdc++.h>
using namespace std;
int dp[1000][10000];
int s1, s2;
int main(){
for(int i = 0; i < 1000; i++){
for(int j = 0; j < 10000; j++){
dp[i][j] = 1000;
}
}
dp[0][0] = 0;
for(int i = 1; i <= 9; i++){
for(int j = 1; j < 1000; j++){
for(int k = 1; k < 10000; k++){
if(j - i >= 0 && k - i * i >= 0)
dp[j][k] = min(dp[j][k], dp[j - i][k - i * i] + 1);
}
}
}
int t; scanf("%d", &t);
while(t--){
scanf("%d %d", &s1, &s2);
if(s1 >= 1000 || s2 >= 10000){
printf("No solution
");
}else if(dp[s1][s2] > 100){
printf("No solution
");
}else{
vector<int>v;
int ans = dp[s1][s2];
while(1){
for(int i = 1; i <= 9; i++){
if(dp[s1 - i][s2 - i * i] + 1 == dp[s1][s2]){
v.push_back(i);
s1 = s1 - i;
s2 = s2 - i * i;
break;
}
}
if(v.size() == ans){
break;
}
}
for(int i: v){
printf("%d", i);
}
puts("");
}
}
}
Shortest Subchain URAL - 1651
题意:给你一个串数字, 表示从第一位置 到最后一个位置走的路径, 问找一个从第一个位置到最后一个位置的最短路径, 且走的边的顺序和给的顺序一样(也就是 后走的边一定不能再先走的边前面)。
题解:
这题看起来好难写, 但是会了建图这题就简单了。
要是没用后面的条件很多直接建图跑个BFS就可以了。但是有了这个条件就无从下手。
我们可以, 按照位置建图, 也就是第一个点的位置与第二个点的位置(i --> i + 1)建立一条有向边且边权为1, 这样可以保证走的路径一定是按照题目的意思。
然后我再找 a[i]再i位置前面离i最近的点建一天权值为0的有向边, 图建好了, 就是简单的迪杰斯特拉了。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 7;
int a[N], n, pos[N];
struct node{
int u, v;
bool operator <(const node a)const{
return v > a.v;
}
};
vector<pair<int, int> >g[N];
priority_queue<node>q;
int dist[N], vis[N], fa[N];
void dij(){
q.push({1, 0});
for(int i = 1; i <= n; i++){
vis[i] = 0;
dist[i] = 1e8;
fa[i] = 0;
}
dist[1] = 0;
while(q.size()){
node cd = q.top();
q.pop();
if(vis[cd.u])continue;
for(auto it: g[cd.u]){
int to = it.first;
int cost = it.second;
if(dist[to] > dist[cd.u] + cost){
dist[to] = dist[cd.u] + cost;
q.push({to, dist[to]});
fa[to] = cd.u;
}
}
}
}
vector<int>v;
int main(){
while(~scanf("%d", &n)){
v.clear();
for(int i = 1; i <= n; i++){
scanf("%d", &a[i]);
g[i].clear();
pos[a[i]] = 0;
}
for(int i = 1; i < n; i++){
g[i].push_back({i + 1, 1});
}
for(int i = 1; i <= n; i++){
if(pos[a[i]]){
g[pos[a[i]]].push_back({i, 0});
}
pos[a[i]] = i;
}
dij();
int x = n;
while(x){
v.push_back(a[x]);
x = fa[x];
}
v.push_back(-1);
reverse(v.begin(), v.end());
for(int i = 1; i < v.size(); i++){
if(v[i] == v[i - 1])continue;
printf("%d ", v[i]);
}
puts("");
}
}
以上是关于训练赛的主要内容,如果未能解决你的问题,请参考以下文章