[ABC384C] Perfect Standings
题面翻译
Takahashi 决定举办一次编程竞赛。
竞赛包含五道题目:A、B、C、D、E,得分分别为 \(a\) 、 \(b\) 、 \(c\) 、 \(d\) 、 \(e\) 。
共有 \(31\) 名参赛者,每人都至少解答了一道题目。
更具体地说,对于字符串 ABCDE
的每个非空子序列(不一定连续),都有一个以该子序列命名的参赛者,他解答了与其名字中字母对应的题目,而没有解答其他题目。
例如,参赛者 A 只解答了题目 A,参赛者 BCE 解答了题目 B、C 和 E。
输入格式
$ a $ $ b $ $ c $ $ d $ $ e $
输出格式
按得分从大到小的顺序打印参赛者的姓名。参与者获得的分数是他们所解决问题的分数的总和。
如果两个参与者获得的分数相同,则首先打印名字在字典中较小的参与者。
制約
- $ 100\leq\ a\leq\ b\leq\ c\leq\ d\leq\ e\leq\ 2718 $
- 入力はすべて整数
解题思路
//abc384c
#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
int grade[10], idx = 0;
bool flag[10];
string s1[5] = {"A", "B", "C", "D", "E"};
struct st{string a;int val;
}c[50];bool cmp(st x, st y){if(x.val == y.val) return x.a < y.a;else return x.val > y.val;
}//递归函数包括,当前枚举到第几个字母,当前枚举构成的字符串,当前构成字符串的值
void f(int alpha, string s, int val){for(int i = alpha; i < 5; i++){string temp = s + s1[i];int v = val + grade[i];c[++idx].val = v;c[idx].a = temp;f(i+1, temp, v);}
}int main(){for(int i = 0; i < 5; i++) cin >> grade[i];//创造序列f(0, "", 0);sort(c+1, c+idx+1, cmp);for(int i = 1; i <= idx; i++) cout << c[i].a << endl;return 0;
}
[ABC384D] Repeated Sequence
题面翻译
给定常数 \(N,S\) 与 \(n\) 个数 \(a_1,a_2,\cdots a_N\),现有无穷项数列 \(A\) 满足
求是否存在两个正整数 \(i<j\) 满足 \(\displaystyle \sum_{k=i}^j A_k=S\)。
制約
- $ 1\leq\ N\leq2\times10\ ^ 5 $
- $ 1\leq\ A\ _ i\leq\ 10\ ^ 9 $
- $ 1\leq\ S\leq\ 10\ ^ {18} $
- 入力はすべて整数
解题思路
无穷项数列\(A\)实际上是一直重复原有数列的值。
满足条件的情况可以简化为:
原序列中的部分序列加上\(x\)倍的\(\displaystyle \sum_{k=i}^n A_k\)(其中\(x\in[0,∞]\))
其中,部分序列有两种情况。
- 中间连续的一段
- 开头一段加上结尾一段
因此,可以先让\(s = s\%sum(n)\),再处理剩下的和
对于这两种情况,可以通过开两倍空间,重复原序列,生成新一段的前缀和,合并成一种情况
利用双指针枚举 ,一旦序列中有一段满足要求即输出结果,时间复杂度为\(O(4*n)\)
//abc384d
#include<stdio.h>
#include<iostream>
using namespace std;
const int N = 400010;
typedef long long ll;
ll a[N], sum1[N], sum2[N];int main(){ll n, s;cin >> n >> s;for(ll i = 1; i <= n; i++){cin >> a[i];sum1[i] = sum1[i-1] + a[i];}s = s % sum1[n];//前缀和开两倍大,处理后一段的值for(ll i = 1; i <= n; i++) sum1[n+i] = sum1[n] + sum1[i];//由中间连续的一段构成(双指针判断)ll l = 1, r = 2;while(r <= 2 * n){while(r <= 2 * n && sum1[r] - sum1[l-1] < s) r++;if(sum1[r] - sum1[l-1] == s && l != r){cout << "Yes" << endl;return 0;}l++;}cout << "No" << endl;return 0;
}
[ABC384E] Takahashi is Slime 2
题面翻译
有一个网格,水平行数为 \(H\) ,垂直列数为 \(W\) 。令 \((i, j)\) 表示从上往下第 \(i\) 行 \((1\leq i\leq H)\) 行、从左往右第 \(j\) 列 \((1\leq j\leq W)\) 列的单元格。
最初,单元格 \((i,j)\) 中有一只史莱姆,强度为 \(S _ {i,j}\) ,而 Takahashi 是单元格 \((P,Q)\) 中的史莱姆。
在执行以下任意次数(可能是零次)操作后,找出 Takahashi 的最大可能强度:
- 在与他相邻的史莱姆中,选择一个强度严格小于他强度的 \(\dfrac{1}{X}\) 倍的史莱姆并吸收它。结果,被吸收的史莱姆消失,而高桥的实力则增加了吸收史莱姆的实力。
执行上述动作时,消失的史莱姆留下的空隙会立即被高桥填补,消失的史莱姆之前相邻的史莱姆(如果有的话)将与高桥重新相邻。
制約
- $ 1\leq\ H,W\leq500 $
- $ 1\leq\ P\leq\ H $
- $ 1\leq\ Q\leq\ W $
- $ 1\leq\ X\leq10^9 $
- $ 1\leq\ S\ _\ {i,j}\leq10^{12} $
- 入力はすべて整数
解题思路
可以发现,史莱姆的实力一定是越来越强。如果要满足\(s[i][j]<power/t\)的条件,那么当\(power\)的值越大时,符合条件的格子越多。
同时,\(s[i][j]\)的值越小,更有可能符合要求。因此在前期应该倾向于先扩散\(s[i][j]\)小的格子,每次在可选的点列表当中选择一个\(s[i][j]\)最小的点,如果满足条件就吸收该格子,并且将四周的格子列入待选列表。
具体代码实现为:
- 建立结构体存储点的横纵坐标以及该点强度值;
- 利用优先队列存储能走到的点,小根堆存储能够保证每次队头元素都是强度值最小的;
- 从起点开始进行bfs扩散,直到所有能够扩散的点都遍历,程序结束。
//abc384e
#include<stdio.h>
#include<iostream>
#include<queue>
#include<vector>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;ll a[505][505];
ll ans = 0;
bool flag[505][505];struct slime{int x, y;ll val;bool operator < (const slime& a) const{return val > a.val;}
}s[250010];//小顶堆
priority_queue<slime> q;
int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0};
int h, w, t, x, y;void bfs(){while(!q.empty()){slime temp = q.top();q.pop();if(a[temp.x][temp.y] < (ans % t? ans / t + 1: ans / t) || (temp.x == x && temp.y == y)){ans += a[temp.x][temp.y];for(int i = 0; i < 4; i++){int xx = temp.x + dx[i];int yy = temp.y + dy[i];if(1 <= xx && xx <= h && 1 <= yy && yy <= w && !flag[xx][yy]){q.push({xx, yy, a[xx][yy]});flag[xx][yy] = 1;}}}}
}int main(){cin >> h >> w >> t;cin >> x >> y;for(int i = 1; i <= h; i++)for(int j = 1; j <= w; j++)cin >> a[i][j];q.push({x, y, a[x][y]});flag[x][y] = 1;bfs();cout << ans << endl;return 0;
}
[ABC384F] Double Sum 2
题面翻译
定义 \(f(x)=\frac{x}{\text{lowbit}(x)}\)。其中,\(\text{lowbit}(x)\) 表示 \(x\) 二进制中最低位的 \(1\) 所表示的数,可以通过 x&(-x)
求得。
现给定一个长度为 \(n\) 的序列 \(a\),求 \(\sum_{i=1}^{n}\sum_{j=i}^{n}f(a_i+a_j)\)。
\(n\le 2\times 10^5,a_i\le 10^7\)。
制約
- $ 1\le\ N\le\ 2\times\ 10^5 $
- $ 1\le\ A_i\le\ 10^7 $
- 入力は全て整数
解题思路
如果暴力解决,时间复杂度为\(O(n^2)\)
分析可得到
- 当\(lowbit(a_i)!=lowbit(b_i)\)时,\(lowbit(a_i+b_i)=min(lowbit(a_i), lowbit(b_i))\)
先处理出来所有元素的\(lowbit\)值,从大到小排序,构成新序列\(T\)。
对于序列中元素\(T_i\)而言,以其值作为分母,对答案的贡献值可以表示成\(({\sum_{idx=1}^{i-1}a_{idx}}+(i-1)*a_i)/T_i\)
其中\(a\)序列以按照lowbit值进行重新排序。(理想状态下,所有元素的lowbit值都不相等的情况下)
- 当\(lowbit(a_i)==lowbit(b_i)\)时,需要找到\(lowbit(a_i+b_i)\)值。
从\(lowbit(a_i)\)往前,可以发现如果\(a_i\)和\(b_i\)的相同位上的数都不一样的话,相加之后都会产生0的结果,因此需要找到从右往左第一位相同位。
需要用到trie树or桶实现该部分问题。
最后把两部分处理的结果加起来即为答案。