A
考虑最小值把区间疯狂划分,那就是说明笛卡尔树相同啦
/* ***********************************************
Author :BPM136
Created Time :7/18/2019 12:10:03 PM
File Name :A.cpp
************************************************ */
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<iomanip>
#include<bitset>
#include<queue>
#include<ctime>
#include<set>
#include<map>
#include<list>
#include<vector>
#include<cassert>
#include<string>
#include<cinttypes>
#include<cstdint>
#include<array>
#define SZ(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
#define USE_CIN_COUT ios::sync_with_stdio(0)
using namespace std;
typedef long long ll;
typedef double db;
typedef long double ld;
typedef unsigned int ui;
typedef unsigned long long ull;
int const N = 100005;
int v[N], ta[N], tb[N];
int fa[N][20], fb[N][20];
int a[N], b[N];
int RMQ(int R[], int f[N][20], int l,int r)
{
int k=0;
while (1<<(k+1)<=r-l+1) k++;
int x=f[l][k],y=f[r-(1<<k)+1][k];
return R[x]<R[y]?x:y;
}
void DP(int n, int f[N][20], int R[])
{
for (int i=1;i<=n;i++) f[i][0]=i;
for (int j=1;(1<<j)<=n;j++)
for (int i=1;i+(1<<j)-1<=n;i++)
{
int x=f[i][j-1],y=f[i+(1<<(j-1))][j-1];
f[i][j]=R[x]<R[y]?x:y;
}
}
bool solve(int l, int r) {
if (l >= r)
return 1;
auto posa = RMQ(a, fa, l, r);
auto posb = RMQ(b, fb, l, r);
if (posa != posb)
return 0;
return solve(l, posa - 1) && solve(posa + 1, r);
}
bool check(int lim) {
DP(lim, fa, a);
DP(lim, fb, b);
return solve(1, lim);
}
int main() {
int n;
while (cin >> n) {
for (int i = 1; i <= n; ++i)
cin >> a[i];
for (int i = 1; i <= n; ++i)
cin >> b[i];
int ans = 0, l = 1, r = n;
while (l <= r) {
int mid = (l + r) >> 1;
if (check(mid)) {
ans = mid;
l = mid + 1;
} else
r = mid - 1;
}
cout << ans << '\n';
}
return 0;
}
B
大力积分,化一下式子,答案就会化成
∑i=1n1ai∏j=1,j!=inaj−ai∗(−1)n+1
\sum_{i=1}^n \frac{1}{ a_i \prod_{j=1,j != i}^{n} a_j-a_i} *(-1)^{n+1}
i=1∑nai∏j=1,j!=inaj−ai1∗(−1)n+1
/* ***********************************************
Author :BPM136
Created Time :7/18/2019 1:12:32 PM
File Name :B.cpp
************************************************ */
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<iomanip>
#include<bitset>
#include<queue>
#include<ctime>
#include<set>
#include<map>
#include<list>
#include<vector>
#include<cassert>
#include<string>
#include<cinttypes>
#include<cstdint>
#include<array>
#define SZ(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
#define USE_CIN_COUT ios::sync_with_stdio(0)
using namespace std;
typedef long long ll;
typedef double db;
typedef long double ld;
typedef unsigned int ui;
typedef unsigned long long ull;
ll const mod = 1e9 + 7;
ll KSM(ll a, ll k) {
ll ret = 1;
for ( ; k; k >>= 1, a = a * a % mod)
if (k & 1)
ret = ret * a % mod;
return ret;
}
ll a[10005];
int main() {
// cerr << KSM(5040, mod - 2) << '\n';
int n;
while (cin >> n) {
for (int i = 1; i <= n; ++i)
cin >> a[i];
ll ans = 0;//-KSM(2, mod - 2);
for (int i = 1; i <= n; ++i) {
ll tmp = a[i];
for (int j = 1; j <= n; ++j)
if (i != j) {
tmp = tmp * (a[i] * a[i] % mod - a[j] * a[j] % mod) % mod;
tmp = (tmp + mod) % mod;
}
ans += KSM(tmp, mod - 2);
ans %= mod;
}
if (n % 2 == 0)
ans = -ans;
cout << (ans * KSM(2, mod - 2) % mod + mod) % mod << '\n';
}
return 0;
}
C
虽然复杂度是错的,但是不知道为啥就过了x(来自小洛洛
每次投影到低一维的空间上,然后对中心点做垂直,发现不在面上就继续做垂直
可能出题人没有想过这种做法,于是就跑过去了,复杂度O(n2)O(n^2)O(n2)
#include <iostream>
#include <cstdint>
#include <algorithm>
#include <string>
#include <vector>
#include <cstdlib>
using i64 = int64_t;
// using i64 = __int128;
i64 gcd(i64 a, i64 b) {
while (b != 0) {
a %= b;
std::swap(a, b);
}
return a;
}
struct Frac {
i64 p, q;
private:
Frac (i64 p, i64 q): p(p), q(q) {}
public:
Frac (i64 p = 0): Frac(p, 1) {}
static Frac from(i64 p, i64 q) {
if (q < 0) {
p = -p;
q = -q;
}
auto g = gcd(p < 0 ? -p : p, q);
return { p / g, q / g };
}
// Frac sqr () const {
// return { p * p, q * q };
// }
// Frac operator+ (const Frac &rhs) const {
// return from(p * rhs.q + q * rhs.p, q * rhs.q);
// }
// Frac operator- (const Frac &rhs) const {
// return from(p * rhs.q - q * rhs.p, q * rhs.q);
// }
// Frac operator/ (i64 t) const {
// return from(p, q * t);
// }
friend std::ostream &operator<< (std::ostream &os, const Frac &self) {
return self.q == 1 ? os << (int64_t)self.p : os << (int64_t)self.p << '/' << (int64_t)self.q;
}
};
std::vector<i64> solve(int n, int m, const std::vector<i64> &v, int &realn) {
auto p = std::vector<i64>(n, 0);
auto orz = std::vector<char>(n, 0);
bool orzed;
i64 s, curn;
do {
orzed = false;
s = curn = 0;
for (int i = 0; i < n; ++i)
if (!orz[i]) {
++curn;
s += v[i];
}
for (int i = 0; i < n; ++i)
if (!orz[i]) {
auto x = curn * v[i] + m - s;
if (x < 0) {
orz[i] = orzed = true;
p[i] = 0;
} else
p[i] = x;
}
} while (orzed);
realn = curn;
return p;
}
int main () {
std::ios::sync_with_stdio(false);
int n, m;
while (std::cin >> n >> m) {
auto v = std::vector<i64>(n);
for (auto &a: v) {
int t;
std::cin >> t;
a = t;
// std::cin >> a;
}
int realn;
auto p = solve(n, m, v, realn);
i64 ans = 0;
for (int i = 0; i < n; ++i) {
auto c = p[i] - (i64)realn * v[i];
ans += c * c;
}
std::cout << Frac::from(ans, (i64)realn * realn * m * m) << '\n';
}
return 0;
}
D
答案可以化为
12m∑i=1n∏j=1m(1−(−1)∣ai,j and x∣+1)
\frac {1} {2 ^ m} \sum_{i = 1} ^ {n} \prod_{j = 1} ^ {m} (1 - (-1) ^ {|a_{i,j} \ and \ x| + 1})
2m1i=1∑nj=1∏m(1−(−1)∣ai,j and x∣+1)
这里的∣a∣|a|∣a∣表示aaa的二进制中1的个数
上面这个等式来源于qls
然后他告诉我
∣a and b∣+∣c and b∣=∣(a xor c) and b∣
|a \ and \ b| + |c \ and \ b| = |(a \ xor \ c) \ and \ b|
∣a and b∣+∣c and b∣=∣(a xor c) and b∣
那么我们把上面那个式子展开,就可以求啦
最后加上的
(−1)∣a xor x∣
(-1)^{|a \ xor \ x|}
(−1)∣a xor x∣
是FWT的系数
那么我们只要单独FWT一下就好了
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int const N = 2200005;
ll const mod = 1e9 + 7;
ll KSM(ll a, ll k) {
ll ret = 1;
for ( ; k; k >>= 1, a = a * a % mod)
if (k & 1)
ret = ret * a % mod;
return ret;
}
ll F[N];
int a[11];
int n, m, K;
int val;
void dfs(int x, int one) {
if (x == m) {
F[val] += one;
// cerr << val << ' ' << one << '\n';
return;
}
int tmp = val;
val ^= a[x];
dfs(x + 1, -one);
val = tmp;
dfs(x + 1, one);
}
void FWT(ll *P, int len) {
for (int i = 1; i < len; i <<= 1)
for (int p = i << 1, j = 0; j < len; j += p)
for (int k = 0; k < i; ++k) {
int x = P[j + k], y = P[j + k + i];
P[j + k] = 1ll*(x + y) % mod;
P[j + k + i]=1ll*(x - y + mod) % mod;
}
}
int main() {
ios::sync_with_stdio(0);
while (cin >> n >> m >> K) {
for (int i = 0; i < (1 << K); ++i)
F[i] = 0;
for (int i = 1; i <= n; ++i) {
for (int j = 0; j < m; ++j)
cin >> a[j];
dfs(0, 1);
}
// for (int i = 0; i < (1 << K); ++i)
// cerr << F[i] << ' ';
// cerr << '\n';
for (int i = 0; i < (1 << K); ++i)
F[i] = (F[i] % mod + mod) % mod;
FWT(F, 1 << K);
// for (int i = 0; i < (1 << K); ++i)
// cerr << F[i] << ' ';
// cerr << '\n';
// cerr << (1 << m) << '\n';
ll inv = KSM(1 << m, mod - 2);
ll c = 1;
int ans = 0;
for (int i = 0; i < (1 << K); ++i) {
ans ^= 1LL * c * F[i] % mod * inv % mod;
c = c * 3 % mod;
}
cout << ans << '\n';
}
}
E
这题非常的奥妙重重
就是给你一堆的AB和BA,然后插进去,问有多少个A和B构成的字符串满足可以被分成(可以是不连续的)长度为2的子序列,其中n个是AB,m个是BA
那我们考虑一个一个字符往里面填
假如这个字符是A,那么我们应该优先用AB里面的A
对于B来说就是优先用BA的B
那么任意时刻我们应该剩下一些A,B,AB,BA
那么我们填的A和B就应该按照刚刚的贪心顺序填。
那么我们就可以DP了
#include <bits/stdc++.h>
using namespace std;
int const N = 2005;
int const mod = 1e9 + 7;
int f[N][N];
inline void update(int& a, int b) {
a += b;
if (a >= mod)
a -= mod;
}
int main() {
int n, m;
while (cin >> n >> m) {
int s = (n + m);
for (int i = 0; i <= s; ++i)
for (int j = 0; j <= s; ++j)
f[i][j] = 0;
f[0][0] = 1;
for (int i = 0; i <= s; ++i)
for (int j = 0; j <= s; ++j)
if (f[i][j]) {
int cnta = 0, cntb = 0;
int AB = max(n - i, 0);
int B = min(i, n) - max(j - m, 0);
cnta += AB;
cntb += max(B, 0);
int BA = max(m - j, 0);
int A = min(j, m) - max(i - n, 0);
cnta += max(A, 0);
cntb += BA;
// cerr << i << ' ' << j << ' ' << cnta << ' ' << cntb << '\n';
if (cnta > 0)
update(f[i + 1][j], f[i][j]);
if (cntb > 0)
update(f[i][j + 1], f[i][j]);
}
cout << f[s][s] << '\n';
}
}
F
题解问小洛洛(((反正是水题
def main():
try:
while True:
print(solve(*map(int, input().split(' '))))
except EOFError as e:
pass
def cross(x1, y1, x2, y2):
return x1 * y2 - y1 * x2
def solve(x1, y1, x2, y2, x3, y3):
S2 = abs(cross(x2 - x1, y2 - y1, x3 - x1, y3 - y1))
return S2 * 11
main()
G
魔鬼题,待补
H
线性基题,首先我们先对n个数构建一个线性基B1,那么如果对于不构成线性基里面的数,肯定可以被线性基里面的数线性表出,那么方案自然是2n−r−12^{n-r-1}2n−r−1,这里的rrr是线性基的秩
那对于线性基里面的数呢?那就要考虑之前的时候这个数在刚刚的统计里面用了多少次,那也就是说,对于所有其他的数,能不能把这个数线性表出,如果可以自然和非基里面的答案一样,否则使用次数就是0,这里我们可以先对于其他的数构建一个线性基B2,每次把基里面的其他的数暴力插进去
#include <bits/stdc++.h>
using namespace std;
#define SZ(x) ((int)(x).size())
using ll = long long;
using ull = unsigned long long;
int const mod = 1e9 + 7;
ll KSM(ll a, ll k) {
ll ret = 1;
for (; k; k >>= 1, a = a * a % mod)
if (k & 1)
ret = ret * a % mod;
return ret;
}
struct L_B {
ull d[61], p[61];
int cnt;
L_B() {
memset(d, 0, sizeof(d));
memset(p, 0, sizeof(p));
cnt = 0;
}
bool insert(ull val) {
for (int i = 63; i >= 0; --i)
if (val & (1ULL << i)) {
if (!d[i]) {
d[i] = val;
break;
}
val ^= d[i];
}
return val > 0;
}
};
L_B merge(L_B const& n1, L_B const& n2) {
auto ret = n1;
for (int i = 63; i >= 0; --i)
if (n2.d[i])
ret.insert(n2.d[i]);
return ret;
}
int main() {
ios::sync_with_stdio(0);
int n;
while (cin >> n) {
auto a = vector<ull>(n);
for (auto& v : a)
cin >> v;
auto B1 = L_B(), B2 = L_B();
auto B1_pos = vector<int>();
int ans = 0, r = 0;
for (int i = 0; i < n; ++i)
if (B1.insert(a[i])) {
++r;
B1_pos.push_back(i);
} else {
B2.insert(a[i]);
++ans;
}
for (int i = 0; i < SZ(B1_pos); ++i) {
auto tB = B2;
for (int j = 0; j < SZ(B1_pos); ++j)
if (i != j)
tB.insert(a[B1_pos[j]]);
if (!tB.insert(a[B1_pos[i]]))
++ans;
}
cout << ans * KSM(2, n - r - 1) % mod << '\n';
}
}
I
这种傻逼题我竟然在比赛的时候没有看到
把y离散了,然后大力DP就完事了
#include <bits/stdc++.h>
using namespace std;
#define SZ(x) ((int)(x).size())
#define all(x) (x).begin(), (x).end()
using ll = long long;
inline ll max(ll const& a, ll const& b) {
return a > b ? a : b;
}
int const N = 100005;
ll mx[N << 2], lz[N << 2];
int ql, qr;
ll suma[N], sumb[N], pos[N], f[N];
inline void pushdown(int k) {
mx[k << 1] += lz[k];
mx[k << 1 | 1] += lz[k];
lz[k << 1] += lz[k];
lz[k << 1 | 1] += lz[k];
lz[k] = 0;
}
inline void pushup(int k) {
mx[k] = max(mx[k << 1], mx[k << 1 | 1]);
}
ll query(int k, int l, int r) {
if (ql > qr)
return 0;
if (ql <= l && r <= qr)
return mx[k];
if (lz[k])
pushdown(k);
int mid = (l + r) >> 1;
ll ret = 0;
if (ql <= mid)
ret = max(ret, query(k << 1, l, mid));
if (qr > mid)
ret = max(ret, query(k << 1 | 1, mid + 1, r));
pushup(k);
return ret;
}
void add(int k, int l, int r, ll val) {
if (ql <= l && r <= qr) {
mx[k] += val;
lz[k] += val;
return;
}
if (lz[k])
pushdown(k);
int mid = (l + r) >> 1;
if (ql <= mid)
add(k << 1, l, mid, val);
if (qr > mid)
add(k << 1 | 1, mid + 1, r, val);
pushup(k);
}
void motifiy(int k, int l, int r, int posy, ll val) {
if (l == r) {
mx[k] = max(mx[k], val);
return;
}
if (lz[k])
pushdown(k);
int mid = (l + r) >> 1;
if (posy <= mid)
motifiy(k << 1, l, mid, posy, val);
else
motifiy(k << 1 | 1, mid + 1, r, posy, val);
pushup(k);
}
struct point {
int x, y;
int a, b;
bool operator < (point const& oth) const {
if (x == oth.x)
return y < oth.y;
return x < oth.x;
}
};
int main() {
point v;
int n;
while (cin >> n) {
auto mp = map<int, vector<point>>();
auto det = vector<int>();
det.push_back(0);
for (int i = 0; i < n; ++i) {
cin >> v.x >> v.y >> v.a >> v.b;
mp[v.x].emplace_back(v);
det.push_back(v.y);
}
sort(det.begin(), det.end());
det.erase(unique(det.begin(), det.end()), det.end());
for (int i = 0; i <= SZ(det) * 4; ++i)
mx[i] = lz[i] = 0;
for (auto& b : mp) {
auto& tp = b.second;
sort(tp.begin(), tp.end());
for (int i = 0; i < SZ(tp); ++i) {
suma[i] = tp[i].a + (i ? suma[i - 1] : 0);
sumb[i] = tp[i].b + (i ? sumb[i - 1] : 0);
pos[i] = lower_bound(all(det), tp[i].y) - det.begin() + 1;
}
for (int i = 0; i < SZ(tp); ++i) {
ql = 1, qr = pos[i];
f[i] = query(1, 1, SZ(det)) + sumb[i] + suma[SZ(tp) - 1] - suma[i];
}
ql = 1, qr = pos[0] - 1;
add(1, 1, SZ(det), suma[SZ(tp) - 1]);
for (int i = 0; i < SZ(tp); ++i) {
ql = pos[i], qr = (i == SZ(tp) - 1) ? SZ(det) : (pos[i + 1] - 1);
add(1, 1, SZ(det), sumb[i] + suma[SZ(tp) - 1] - suma[i]);
}
for (int i = 0; i < SZ(tp); ++i)
motifiy(1, 1, SZ(det), pos[i], f[i]);
/////DEBUG
// for (int i = 1; i <= SZ(det); ++i) {
// ql = i, qr = i;
// cerr << query(1, 1, SZ(det)) << ' ';
// }
// cerr << '\n';
}
ql = 1, qr = SZ(det);
cout << query(1, 1, SZ(det)) << '\n';
}
}
J
傻逼题
def main():
try:
while True:
x, a, y, b = map(int, input().split(' '))
t1, t2 = x * b, a * y
if t1 == t2:
print('=')
elif t1 < t2:
print('<')
else:
print('>')
except EOFError as e:
pass
main()