E - Mayor's posters
线段树
引入:离散化
将l,r储存在一个数组,排序去重,以l,r为导引在数组寻找值的位置,也就是映射
思路:线段树+离散化
离散化时需要进行 Hash[cnt++] = e[i].ri + 1; 不然出现单个数直接会直接覆盖
查询操作:遍历线段树所有结点,涂有颜色且未被访问过,答案++
#include
#include
#include
#include
#define maxn 20005
using namespace std;
struct data{
int le, ri;
}e[maxn];
int book[maxn << 3], Hash[maxn << 1], t[maxn << 3], cnt;
void pushdown(int rt){
if (t[rt] != -1){
t[rt << 1] = t[rt << 1 | 1] = t[rt];
t[rt] = -1;
}
}
void updata(int num, int l, int r, int L, int R, int rt){
if (L >= l && R <= r){ //若在区间内染色
t[rt] = num;
return;
}
pushdown(rt);
int m = (L + R) >> 1;
if (l <= m)
updata(num, l, r, L, m, rt << 1);
if (r > m)
updata(num, l, r, m + 1, R, rt << 1 | 1);
}
void query(int L, int R, int rt)
{
if (t[rt] != -1){ //遍历线段树所有结点,涂有颜色且未被访问过,答案++
if (!book[t[rt]]){
cnt++;
book[t[rt]] = 1;
}
return; //已经一个结点涂有颜色,则区间涂有颜色,不需要遍历子节点
}
if (L == R)
return;
int m = (L + R) >> 1;
query(L, m, rt << 1);
query(m + 1, R, rt << 1 | 1);
}
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
int n;
scanf("%d", &n);
memset(book, 0, sizeof(book));
memset(t, -1, sizeof(t));
cnt = 1;
for (int i = 0; i < n; i++)
{
scanf("%d%d", &e[i].le, &e[i].ri);
Hash[cnt++] = e[i].le;
Hash[cnt++] = e[i].ri;
Hash[cnt++] = e[i].ri + 1; //出现单个数直接会直接覆盖
}
sort(Hash + 1, Hash + cnt + 1);
int len = unique(Hash + 1, Hash + cnt + 1) - Hash;
//unique函数将数组中相邻的重复元素去除。然而其本质是将重复的元素移动到数组的末尾,
//最后再将迭代器指向第一个重复元素的下标。
//len=去重后最后一个不重复元素的地址
cnt = len;
sort(Hash + 1, Hash + cnt + 1);
len = cnt, cnt = 0;
for (int i = 0; i < n; i++){
int le = lower_bound(Hash, Hash + len, e[i].le) - Hash; //查找第一个不小于e[i].len的地址
int ri = lower_bound(Hash, Hash + len, e[i].ri) - Hash;
updata(i, le, ri, 1, len, 1);
}
query(1, len, 1);
printf("%d\n", cnt);
}
return 0;
}
Codeforces Round 861 (Div. 2)
Lucky Numbers
思路:100为一个循环,在i < 100&&(i+a)<=b前提下,寻找区间一个数中最大数-最小数的最大值的数即可
#include
using namespace std;
int arr[100];
int Find(int x) {
int y = x;
int Max = -1;
int Min = 0x3f3f3f;
while (y != 0) {
int z = y % 10;
y /= 10;
if (z > Max)
Max = z;
}
while (x != 0) {
int z = x % 10;
x /= 10;
if (z < Min)
Min = z;
}
return Max - Min;
}
int main()
{
ios::sync_with_stdio(false);
int t;
cin >> t;
while (t--) {
int a, b;
cin >> a >> b;
arr[0] = a;
for (int i = 1; i < 100&&(i+a)<=b; i++) {
arr[i] = a + i;
}
int Max = -1;
int flag = 0;
for (int i = 0; i < 100 && (i + a) <= b; i++) {
int z = Find(arr[i]);
if (z == 9) {
flag = i;
break;
}
if (z > Max) {
flag = i;
Max = Find(arr[i]);
}
}
cout << arr[flag] << '\n';
}
return 0;
}
B. Playing in a Casino
错解:动态二维数组,时间超限
#include
#include
#include
using namespace std;
int main()
{
ios::sync_with_stdio(false);
int t;
cin >> t;
while (t--) {
long long sum=0;
int n, m;
cin >> n >> m;
vector > a(n+1, vector(m+1));
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cin >> a[i][j];
}
}
if (n == 1) {
cout << "0\n";
continue;
}
for (int i = 1; i <= n; i++) {
for (int j = i + 1; j <= n; j++) {
for (int k = 1; k <= m; k++) {
sum += abs(a[i][k] - a[j][k]);
}
}
}
cout << sum <<'\n';
}
return 0;
}
#include
#include
#include
#include
#include
using namespace std;
using LL = long long;
int main() {
cin.tie(0);
cout.tie(0);
ios::sync_with_stdio(0);
int T;
cin >> T;
while (T--) {
int n, m;
cin >> n >> m;
vector > a(m);
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
int x;
cin >> x;
a[j].push_back(x);
}
}
LL ans = 0;
for (int i = 0; i < m; i++) {
sort(a[i].begin(), a[i].end());
LL sum = accumulate(a[i].begin(), a[i].end(), 0LL);
LL pre = 0;
for (int j = 0; j < n; j++) {
ans += 1LL * j * a[i][j] - pre;
pre += a[i][j];
ans += sum - pre - 1LL * (n - j - 1) * a[i][j];
}
}
cout << ans / 2 << '\n';
}
}
思路:将每一行当作列存储,排序存储的行,
考虑到绝对值和t题目中行行之间都会组合
sumi=b0+b1+...+bi得到存储的行值为i*bi-sumi相加,得到答案为行值相加
公式举例:c>b>a
|a-b|+|b-c|+|a-c|--->b-a+b+c-b+c-a--->2*c+b-2*a
#include
#include
#include
#include
#include
using namespace std;
using LL = long long;
int T, n, m;
LL work(vector& b)
{
LL res = 0;
int len = b.size();
LL sum = 0;
for (int i = 0; i < len; i++){
res = res + (1LL * b[i] * i - sum);
sum += b[i];
}
return res;
}
LL solve() {
cin >> n >> m;
vector > a(m, vector());
int x;
for (int i = 1; i <= n; i++) {
for (int j = 0; j < m; j++) {
cin >> x;
a[j].push_back(x); //行当作列储存
}
}
LL res = 0;
for (int j = 0; j < m; j++) {
sort(a[j].begin(), a[j].end()); //排序
res += work(a[j]);
}
return res;
}
int main()
{
cin.tie(0)->sync_with_stdio(false);
cin >> T;
while (T--){
cout << solve() <<'\n';
}
}
引入:高精度加减乘除及比较模板
#include
#include
using namespace std;
struct bign {
int d[1000];
int len;
bign() {
memset(d, 0, sizeof(d));
len = 0;
}
};
bign add(bign a, bign b) {
bign c;
int carry = 0;
for (int i = 0; i < a.len || i < b.len; i++) {
int t = a.d[i] + b.d[i] + carry;
c.d[c.len++] = t % 10;
carry = t / 10;
}
if (carry != 0) {
c.d[c.len++] = carry;
}
return c;
}
bign sub(bign a, bign b) {
bign c;
for (int i = 0; i < a.len || i < b.len; i++) {
if (a.d[i] < b.d[i]) {
a.d[i + 1]--;
a.d[i] += 10;
}
c.d[c.len++] = a.d[i] - b.d[i];
}
//去掉高位0
while (c.len > 1 && c.d[c.len - 1] == 0) {
c.len--;
}
return c;
}
bign mul(bign a, int b) {
bign c;
int carry = 0;
for (int i = 0; i < a.len; i++) {
int t = a.d[i] * b + carry;
c.d[c.len++] = t % 10;
carry = t / 10;
}
while (carry != 0) {
c.d[c.len++] = carry % 10;
carry /= 10;
}
return c;
}
bign div(bign a, int b) {
bign c;
int r = 0;
c.len = a.len; //商的位数与除数一一对应,不够除为0
for (int i = a.len - 1; i >= 0; i--) {
int t = a.d[i] + r * 10;
c.d[i] = t / b;
r = t % b;
}
while (c.len > 1 && c.d[c.len - 1] == 0) {
c.len--;
}
c.d[c.len] = r; //利用多余数组储存余数
return c;
}
void print(bign a) {
for (int i = a.len - 1; i >= 0; i--) {
printf("%d", a.d[i]);
}
}
int compare(bign a, bign b) {
if (a.len > b.len) return 1;
else if (a.len < b.len) return -1;
else {
for (int i = a.len - 1; i >= 0; i--) {
if (a.d[i] > b.d[i]) return 1;
else if (a.d[i] < b.d[i]) return -1;
}
}
return 0;
}
int main() {
int n;
scanf("%d", &n);
bign sum, a;
a.d[0] = 1;
a.len = 1;
for (int i = 1; i <= n; i++) {
a = mul(a, i);
sum = add(sum, a);
}
print(sum);
return 0;
}
Java
落实完面向对象,进入集合和泛型,了解Javafx使用