CF920
A
给你一个矩阵(每条边平行坐标轴)的四个点,求出矩阵的面积
直接输入四个x,y 排序,然后(x[2]-x[1])与(y[2]-y[1])的乘积
B
你可以进行以下三种操作:
把一只猫放进0,该位置变成1
把一只猫拿出来 该位置从0变1
把一只猫换到其他位置
问你初始状态变为终状态的最小操作数
只需用两个计数器,分别计算,s中有1与t不同的个数,和t中有1与s不同的个数,然后取最大值即可
C
一个手机 待机每个时间单位消耗a 关机再开机 开机时消耗b
现在有一个操作序列,在操作序列时刻,必须开机
现在给你剩余电量,问你可不可以完成所有操作
直接贪心模拟 每次取待机时间与开机的较小值,看最后和电量大小关系
D
给你一个大小为n的数列a,再给你一个大小为m的备选数列c,让你求sigma(abs(ai-ci))的最大值
我的做法不知道能不能被证明为正确,反正a升序,c降序,然后每次比较两个数列两个端点的绝对值差值的较大值,加和
F
根号分治
注意到d>sqrt(n)可以直接枚举,主要处理d<=sqrt(n)的部分
采用三维数组前缀和,每行存公差,每列存余数,每层存idx,分别用加权和不加权存(便于查询,比如计算某一段,直接把前面的先删掉,再用不加权的前缀和把多余权值删掉)
#include <bits/stdc++.h>
using namespace std;
#define int long long
signed main()
{
int tt;
cin >> tt;
while (tt--)
{
int n, q;
cin >> n >> q;
vector<int> p(n + 1, 0);
for (int i = 1; i <= n; i++)
{
cin >> p[i];
}
int bound = sqrt(n);
vector<vector<vector<int>>> presum(bound + 1);
vector<vector<vector<int>>> presumreal(bound + 1);
for (int i = 1; i <= bound; i++)
{
presum[i].resize(i);
presumreal[i].resize(i);
}
for (int i = 1; i <= bound; i++)
{
for (int j = 0; j < i; j++)
{
presum[i][j].resize(n / i + 2);
presumreal[i][j].resize(n / i + 2);
}
}
for (int i = 1; i <= bound; i++)
{
for (int j = 0; j < i; j++)
{
presum[i][j][0] = 0;
presumreal[i][j][0] = 0;
}
for (int j = 1; j <= n; j++)
{
int st = j % i;
int sk = j / i + (j % i != 0);
presum[i][st][sk] = presum[i][st][sk - 1] + p[j] * sk;
presumreal[i][st][sk] = presumreal[i][st][sk - 1] + p[j];
}
}
for (int i = 0; i < q; i++)
{
int s, d, k;
cin >> s >> d >> k;
if (d <= bound)
{
int reals = s % d;
int realbound = s / d + (s % d != 0);
cout << presum[d][reals][realbound + k - 1] - presum[d][reals][realbound - 1] - (presumreal[d][reals][realbound + k - 1] - presumreal[d][reals][realbound - 1]) * (realbound - 1) << " ";
}
else
{
int ans = 0;
for (int j = 0; j < k; j++)
{
ans += p[s + j * d] * (j + 1);
}
cout << ans << " ";
}
}
cout << endl;
}
}