[LGR-123] 洛谷10月月赛 Div.2 T1~3 解析及代码
T1 暴龙的白菜
题目大意:
给定一个字符串,由 1 1 1个 1 1 1, 2 2 2个 2 2 2, 3 3 3个 3 3 3…以此类推,依次拼接而成。
现在有 T T T组询问,每次询问字符串中第 l l l位到第 r r r位上的数字之和,求这些询问的结果。
对于所有数据, 1 ≤ T ≤ 1 0 5 1 \le T \le 10^5 1≤T≤105, 1 ≤ l ≤ r ≤ 1 0 6 1 \le l \le r \le 10^6 1≤l≤r≤106。
思路:
考虑到 l l l和 r r r最大只有 1 0 6 10^6 106,所以我们显然可以把这个字符串构造出来再维护其前缀和。
时间复杂度 O ( n ) O(n) O(n)。
代码:
#include <iostream>
#include <algorithm>
#include <cstring>
#include <stdio.h>
using namespace std;
typedef long long LL;
const int N = 1e6 + 5000;
int l, r, a[N];
LL ans = 0, s[N];
void init() //构造字符串
{
int j = 1, k;
for(int i = 1 ; i <= 9 ; i ++ )
for(k = 1 ; k <= i ; j ++ , k ++ )
a[j] = i;
j ++ ;
for(int i = 10 ; i <= 99 ; i ++ )
for(k = 1 ; k <= i ; j += 2, k ++ )
a[j - 1] = i / 10, a[j] = i % 10;
j ++ ;
for(int i = 100 ; i <= 819 ; i ++ )
for(k = 1 ; k <= i ; j += 3, k ++ )
a[j - 2] = i / 100, a[j - 1] = (i - 100 * a[j - 2]) / 10, a[j] = i % 10;
for(int i = 1 ; i <= 1002375 ; i ++ )
s[i] = s[i - 1] + a[i];
}
int main()
{
int T;
scanf("%d", &T);
init();
while(T -- )
{
ans = 0;
scanf("%d%d", &l, &r);
printf("%lld\n", s[r] - s[l - 1]);
}
return 0;
}
T2 So What Do We Do Now?
题目大意:
给定一棵由 n n n个节点构成的树,记 R i R_i Ri为以节点 i i i为根节点的子树中点权的极差,现在要求你构造一组点权,使得:
- 所有点的点权各不相同;
- 所有点的点权均为整数且在 [ 1 , n ] [1,n] [1,n]中;
- ∑ i = 1 n R i \sum_{i=1}^{n}R_i ∑i=1nRi最小。
对于所有数据, 1 ≤ n ≤ 1 0 6 1 \le n \le 10^6 1≤n≤106。
思路:
显然,由于每个节点的权值各不相同且在 [ 1 , n ] [1,n] [1,n]的范围内,所以在一棵以 i i i节点为根,大小为 s i z e i size_i