训练网址
#include
#include
#include
using namespace std;
int gcd(int a, int b) {
if (b == 0) return a;
return gcd(b, a % b);
}
int a[10], b[10];
int main() {
for (int i = 1; i <= 6; i++) scanf("%d", &a[i]);
for (int i = 1; i <= 6; i++) scanf("%d", &b[i]);
int res = 0;
for (int i = 1; i <= 6; i++) {
for (int j = 1; j <= 6; j++) {
res += a[i] > b[j];
}
}
int d = gcd(res, 36);
res /= d;
printf("%d/%d\n", res, 36 / d);
return 0;
}
#include
#include
#include
using namespace std;
const int maxn = 100010, maxm = 200010;
int h[maxn], e[maxm], ne[maxm], w[maxm], idx;
int sz[maxn];
bool is_candidate[maxn], ok[maxn];
void add(int a, int b, int c) {
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}
int N, K, ans;
int dfs(int u, int fa) {
sz[u] = is_candidate[u] ? 1 : 0;
for (int i = h[u]; i != -1; i = ne[i]) {
int v = e[i];
if (v == fa) continue;
sz[u] += dfs(v, u);
}
return sz[u];
}
void dfs2(int u, int fa) {
if (is_candidate[u]) ok[u] = true;
for (int i = h[u]; i != -1; i = ne[i]) {
int v = e[i];
if (v == fa) continue;
if (sz[v] && K - sz[v]) ok[u] = true;
dfs2(v, u);
}
}
int main() {
memset(h, -1, sizeof h);
scanf("%d%d", &N, &K);
for (int i = 1; i < N; i++) {
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
add(a, b, c), add(b, a, c);
}
for (int i = 1; i <= K; i++) {
int x;
scanf("%d", &x);
is_candidate[x] = true;
}
dfs(1, -1);
dfs2(1, -1);
for (int i = 1; i <= N; i++) {
ans += ok[i] ? 1 : 0;
}
printf("%d\n", ans);
return 0;
}
#include
#include
#include
using namespace std;
const int maxn = 1000010;
int a[maxn], b[maxn], r[maxn];
int N;
bool check() {
for (int i = 1; i < N; i++) {
if (abs(a[i] - b[i]) < r[i]) {
if (a[i] > b[i]) a[i]++, b[i + 1]++;
else a[i + 1]++, b[i]++;
}
else if (abs(a[i] - b[i]) == r[i]) a[i]++, b[i]++;
else {
if (a[i] > b[i]) a[i + 1]++, b[i]++;
else a[i]++, b[i + 1]++;
}
if (abs(a[i] - b[i]) != r[i]) return false;
}
return abs(a[N] - b[N]) == r[N];
}
int main() {
scanf("%d", &N);
for (int i = 1; i <= N; i++) scanf("%d", &r[i]);
if (check()) printf("YES\n");
else printf("NO\n");
return 0;
}
#include
#include
#include
using namespace std;
const int maxn = 1000010;
typedef long long ll;
ll a[maxn], D;
int N;
ll f() {
ll lmost = 0, rmost = 0;
for (int i = 1; i <= N; i++) {
ll x = a[1] + (i - 1LL) * D;
if (x > a[i]) rmost = max(rmost, x - a[i]);
if (x < a[i]) lmost = max(lmost, a[i] - x);
}
return (lmost + rmost) / 2;
}
int main() {
scanf("%d%lld", &N, &D);
D *= 10;
for (int i = 1; i <= N; i++) {
scanf("%lld", &a[i]);
a[i] *= 10;
}
ll ans = f();
D = -D;
ans = min(ans, f());
printf("%lld.%lld\n", ans / 10, ans % 10);
return 0;
}
#include
#include
#include
#include
using namespace std;
const double PI = acos(-1);
const int maxn = 300010;
typedef long long ll;
struct Complex {
double x, y;
Complex operator + (const Complex& t)const {
return { x + t.x, y + t.y };
}
Complex operator - (const Complex& t)const {
return { x - t.x, y - t.y };
}
Complex operator * (const Complex& t)const {
return { x * t.x - y * t.y, x * t.y + y * t.x };
}
}a[maxn], c[maxn];
int rev[maxn], bit, tot;
int b[maxn];
void fft(Complex a[], int inv) {
for (int i = 0; i < tot; i++) {
if (i < rev[i]) swap(a[i], a[rev[i]]);
}
for (int mid = 1; mid < tot; mid <<= 1) {
auto w1 = Complex({ cos(PI / mid), inv * sin(PI / mid) });
for (int i = 0; i < tot; i += mid * 2) {
auto wk = Complex({ 1, 0 });
for (int j = 0; j < mid; j++, wk = wk * w1) {
auto x = a[i + j], y = wk * a[i + j + mid];
a[i + j] = x + y, a[i + j + mid] = x - y;
}
}
}
}
int dif = 30000;
int main() {
int N1, N2, N3;
scanf("%d", &N1);
for (int i = 1; i <= N1; i++) {
int x;
scanf("%d", &x);
a[x + dif].x += 1;
}
scanf("%d", &N2);
for (int i = 1; i <= N2; i++) {
int x;
scanf("%d", &x);
b[x + dif] += 1;
}
scanf("%d", &N3);
for (int i = 1; i <= N3; i++) {
int x;
scanf("%d", &x);
c[x + dif].x += 1;
}
bit = 17;
tot = (1 << bit);
for (int i = 0; i < tot; i++) {
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (bit - 1));
}
fft(a, 1), fft(c, 1);
for (int i = 0; i < tot; i++) a[i] = a[i] * c[i];
fft(a, -1);
ll ans = 0;
//一定要小心,这里是数据范围最大,即60000
//而且,卷积的结果在 a 中,要除以 tot 才对。而且,四舍五入的话(比如round),不要加上 0.5,+0.5意味着舍弃小数部分。
for (int i = 0; i <= 60000; i++) {
ll x = a[2 * i].x / tot + 0.5;
ans += x * b[i];
}
printf("%lld\n", ans);
return 0;
}
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const ll INF = 1e18;
const int maxn = 2010, maxm = 200010;
struct node {
int l, r, id;
ll val;
};
vector<node> q;
ll w[maxn], tr[maxn][maxn], ans[maxm];
int lowbit(int x) {
return x & -x;
}
bool cmp(const node& u, const node& v) {
return u.val < v.val || u.val == v.val && u.id < v.id;
}
int N, M;
void update(int x, int y, ll v) {
while (x) {
int z = y;
while (z <= N) {
tr[x][z] = max(tr[x][z], v);
z += z & -z;
}
x -= x & -x;
}
}
ll query(int x, int y) {
ll res = -INF;
while (x <= N) {
int z = y;
while (z) {
res = max(res, tr[x][z]);
z -= z & -z;
}
x += x & -x;
}
return res;
}
int main() {
scanf("%d%d", &N, &M);
for (int i = 1; i <= N; i++) {
fill(tr[i], tr[i] + N + 1, -INF);
}
for (int i = 1; i <= N; i++) {
scanf("%lld", &w[i]);
w[i] += w[i - 1];
}
for (int i = 1; i <= N; i++) {
for (int j = i; j <= N; j++) {
q.push_back({ i, j, 0, w[j] - w[i - 1] });
}
}
for (int i = 1; i <= M; i++) {
int l, r;
ll x;
scanf("%d%d%lld", &l, &r, &x);
q.push_back({ l, r, i, x });
}
sort(q.begin(), q.end(), cmp);
for (auto p : q) {
int l = p.l, r = p.r, id = p.id;
ll val = p.val;
if (!id) update(l, r, val);
else ans[id] = query(l, r);
}
for (int i = 1; i <= M; i++) {
if (ans[i] != -INF) printf("%lld\n", ans[i]);
else printf("NONE\n");
}
return 0;
}
如果对于每个灯列一个n*n的01矩阵进行高斯消元求解,
总复杂度是O(n^4)的,显然不行.
设矩阵A为系数矩阵,
X为开关操作矩阵(未知数矩阵),
B为结果矩阵(常数矩阵),
那么有A*X=B,
左右同时乘上A^(-1)得:X=A^(-1)*B.
求出A矩阵的逆矩阵A^(-1),
因为B矩阵是n*1的,
所以A^(-1)*B是O(n^2)的,
枚举i,构造Bi,计算第i个灯的答案,
总复杂度是O(n^3)的.
但是n<=500,O(n^3)还是会T,
矩阵求逆 和 矩阵乘法 都需要用bitset优化.
版权声明:本文为CSDN博主「live4m」的原创文章,遵循CC 4.0 BY - SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https ://blog.csdn.net/weixin_44178736/article/details/113361135
#include
#include
#include
#include
using namespace std;
const int maxn = 510;
bitset<maxn * 2> a[maxn];
bitset<maxn> b, inv_a[maxn], ans;
int N;
bool Gauss_inv() {
for (int c = 1; c <= N; c++) {
int t = c;
for (int i = c; i <= N; i++) {
if (a[i][c]) {
t = i;
break;
}
}
if (a[t][c] == 0) return false;
swap(a[t], a[c]);
//小心这个地方要从第一行开始看。大雪菜那个是从 r + 1 行开始,那是因为他没有化成单位矩阵
//但是求逆矩阵必须要化为单位阵。
for (int i = 1; i <= N; i++) {
if (a[i][c] && i != c) {
a[i] ^= a[c];
}
}
}
return 1;
}
// A = B * C
void mul(bitset<maxn>& a, bitset<maxn> b[], bitset<maxn>& c) {
for (int i = 1; i <= N; i++) {
//小心这个地方是与,不是异或。矩阵乘法怎么可以写异或呢!
a[i] = (b[i] & c).count() % 2;
}
}
int main() {
scanf("%d", &N);
for (int i = 1; i <= N; i++) {
a[i][i + N] = 1;
for (int j = 1; j <= N; j++) {
int x;
scanf("%d", &x);
if (x) a[j][i] = 1;
}
}
if (!Gauss_inv()) {
printf("-1\n");
}
else {
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= N; j++) inv_a[i][j] = a[i][j + N];
}
/*for (int i = 1; i <= N; i++) {
for (int j = 1; j <= N; j++) cout << a[i][j + N] << " ";
cout << endl;
}*/
for (int i = 1; i <= N; i++) {
b.reset();
b[i] = 1;
ans.reset();
mul(ans, inv_a, b);
for (int i = 1; i <= N; i++) {
if (ans[i]) printf("%d ", i);
}
printf("\n");
}
}
return 0;
}
(h[i]+h[j])*(j-i)
=(h[j]-(-h[i]))*(j-i)
令a[i]=h[i],b[i]=-h[i],
那么可以转化为计算(a[j]-b[i])*(j-i),
转化为(i,a[i]),(j,b[j])在二维坐标系中围成的矩形面积。本质就是在 y 轴上方选一点,y轴下方选一点,使得举行的面积最大。
对于一个固定的(j,a[j]),选择的(i,b[i])显然位置左下越优.
那么对于(i,b[i])和(j,b[j]),如果i=b[j],
那么(i,b[i])完全可以删去。对于 a 数组也是同理(a数组中的数据,越靠近右上方越优)。
去掉b[]无用点之后,剩下的点一定是对于ib[j].
对于a[1,n],设mid=(l1+r1)/2,
设点(mid,a[mid])在点(pos,b[pos])处获得最大值.
那么对于(mid,a[mid])左边的点(j,a[j]),
他们的最优解点(i,b[i])一定满足i<=pos,
可以用反证法证明,
大概就是如果i>pos,那么(mid,a[mid)的就不是(pos,b[pos])了,
画一下图应该也能证明出来.
假设现在我们已经求出(mid,a[mid])和(pos,b[pos])配对最优,
根据我们上面的结论,我们只需要继续分别计算:
1.a[l1,mid-1]和b[l2,pos]匹配的最大值.
2.a[mid+1,r2]h和b[pos,r2]匹配的最大值.
同(mid,a[mid])与(pos,b[pos])的值,三者取max就是答案,
其中情况1和情况2是子问题,可以递归计算.
#include
#include
#include
#define x first
#define y second
using namespace std;
const int maxn = 1000010;
int N, M;
typedef long long ll;
typedef pair<ll, ll> P;
P a[maxn], b[maxn];
bool del[maxn];
ll cal(int j, int i) {
return (a[j].y - b[i].y) * (a[j].x - b[i].x);
}
ll solve(int l1, int r1, int l2, int r2) {
if (l1 > r1 || l2 > r2) return 1e-18;
int mid = (l1 + r1) / 2, pos = l2;
ll res = cal(mid, pos);
for (int i = l2 + 1; i <= r2; i++) {
ll tmp = cal(mid, i);
if (tmp >= res) {
pos = i;
res = tmp;
}
}
return max(res, max(solve(l1, mid - 1, l2, pos), solve(mid + 1, r1, pos, r2)));
}
int main() {
scanf("%d", &N);
M = N;
for (int i = 1; i <= N; i++) {
scanf("%lld", &a[i].y);
a[i].x = i;
b[i] = { i, -a[i].y };
}
sort(a + 1, a + N + 1);
sort(b + 1, b + N + 1);
int cnt = 0, last = N;
//删掉 a 中多余的点,越靠近右上方越优。
for (int i = N - 1; i >= 1; i--) {
if (a[i].y <= a[last].y) {
del[i] = true;
}
else {
last = i;
}
}
for (int i = 1; i <= N; i++) {
if (!del[i]) {
//注意,这个地方不可以写成 ++cnt, a[cnt] = {cnt, a[i].y},因为原本的位置信息必须要保留。
a[++cnt] = a[i];
}
}
N = cnt;
//删掉 b 中左下方的点。
memset(del, false, sizeof del);
last = 1, cnt = 0;
for (int i = 2; i <= M; i++) {
if (b[i].y >= b[last].y) {
del[i] = true;
}
else {
last = i;
}
}
for (int i = 1; i <= M; i++) {
if (!del[i]) {
b[++cnt] = b[i];
}
}
M = cnt;
printf("%lld\n", solve(1, N, 1, M));
return 0;
}