A B C E F H I J 已补 D G未补
赛场上n^2过掉,简直不可思议。正确的解法就是维护当前这对数能影响的左右位置的区间范围。这可以用笛卡尔树或者单调栈实现。
笛卡尔树版:
#include <iostream>
#include <map>
#include <cstring>
#include <queue>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
#define min(a,b) ((a)<(b)?(a):(b))
const int N = 100010;
int n;
int ax[100010];
int bn[100010];
struct Cartesian_Tree {
struct node {
int id, val, fa;
int son[2];
node() {}
node(int id, int val, int fa) : id(id), val(val), fa(fa) {
son[0] = son[1] = 0;
}
}t[N];
int root,l[N],r[N];
void init() {
t[0] = node(0, 0, 0);
}
void build(int n, int *a) {
for (int i = 1; i <= n; ++i) {
t[i] = node(i, a[i], 0);
}
for (int i = 1; i <= n; ++i) {
int k = i - 1;
while (t[k].val > t[i].val) {
k = t[k].fa;
}
t[i].son[0] = t[k].son[1];
t[k].son[1] = i;
t[i].fa = k;
t[t[i].son[0]].fa = i;
}
root = t[0].son[1];
}
int DFS(int u) {
if (u == 0) return 0;
l[t[u].id] = DFS(t[u].son[0]);
r[t[u].id] = DFS(t[u].son[1]);
return l[t[u].id] + r[t[u].id] + 1;
}
};
Cartesian_Tree t1,t2;
int check(int x) {
t1.init();
t1.build(x, ax);
t2.init();
t2.build(x, bn);
t1.DFS(t1.root);
t2.DFS(t2.root);
for (int i = 1; i <= x; i++) {
if (t1.l[i] != t2.l[i] || t1.r[i] != t2.r[i]) {
return 0;
}
}
return 1;
}
int main(void) {
while (scanf("%d", &n) != EOF) {
for (int i = 1; i <= n; i++) {
scanf("%d", &ax[i]);
}
for (int i = 1; i <= n; i++) {
scanf("%d", &bn[i]);
}
int left = 1;
int right = n;
while (left <= right) {
int mid = (left + right) / 2;
if (check(mid)) {
left = mid + 1;
}
else {
right = mid - 1;
}
}
printf("%d\n", left - 1);
}
}
单调栈标程:
#include <iostream>
#include <map>
#include <cstring>
#include <queue>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
#define min(a,b) ((a)<(b)?(a):(b))
std::vector<int> read(int n) {
std::vector<int> result(n);
std::vector<std::pair<int, int>> stack;
stack.emplace_back(0, -1);
for (int i = 0, a; i < n; ++i) {
scanf("%d", &a);
while (stack.back().first > a) {
stack.pop_back();
}
result[i] = stack.back().second;
stack.push_back(make_pair(a, i));
}
return result;
}
int main() {
int n;
while (scanf("%d", &n) == 1) {
auto a = read(n);
auto b = read(n);
int length = 0;
while (length < n && a[length] == b[length]) {
length++;
}
printf("%d\n", length);
}
}
B:
简单推公式,因为我们无法处理相乘的式子的积分,因为只有相加的式子才可以分开积分,所以首先我们要将式子拆分开,推出一般式,然后再简单的换元一下即可。
#include <iostream>
#include <map>
#include <cstring>
#include <queue>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
#define min(a,b) ((a)<(b)?(a):(b))
const int mod = 1e9 + 7;
long long ax[1100];
long long pow_mod(long long a, long long n, long long m){
if (n == 0) return 1;
long long x = pow_mod(a, n / 2, m);
long long ans = (long long)x * x % m;
if (n % 2 == 1) ans = ans * a % m;
return ans;
}
int main(void) {
int n;
while (scanf("%d", &n) != EOF) {
for (int i = 0; i < n; i++) {
scanf("%lld", &ax[i]);
}
long long ans = 0;
for (int i = 0; i < n; i++) {
long long v = 2 * ax[i]%mod;
long long cnt = 1;
for (int z = 0; z < n; z++) {
if (i == z) continue;
cnt = cnt * ((ax[z] * ax[z] % mod - ax[i] * ax[i]%mod) % mod+mod)%mod;
}
ans =( ans + pow_mod(cnt*v%mod, mod - 2, mod)%mod)%mod;
}
printf("%lld\n", ans);
}
}
C
可以构造出一个拉格朗日函数,但是无奈我看不懂题解,无法将这个n元的函数求解。所以换了别人的思路,首先我们要知道当n大于0时,每当n越大,n减少一点带来的n^2贡献也会越大,这样就很明显了,我们现在总共只有1的费用,所以我们肯定会贪心的让整个序列n^2的最大值尽可能小。所以只要维护一个前缀和,寻找尽可能的最大值即可。
#include <iostream>
#include <map>
#include <cstring>
#include <queue>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
#define maxn 10050
long long ax[maxn];
long long gcd(long long a, long long b){
long long r;
while (b > 0){
r = a % b;
a = b;
b = r;
}
return a;
}
int main(void) {
int n, m;
while (scanf("%d%d", &n, &m) != EOF) {
for (int i = 0; i < n; i++) {
scanf("%lld", &ax[i]);
}
sort(ax, ax + n);
long long sum = ax[n - 1];
int i;
long long suma = 0;
long long sumb = 0;
for (i = n - 2; i >= 0; i--) {
if (sum - (n - 1 - i)*ax[i] > m) {
break;
}
else if (sum - (n - 1 - i)*ax[i] <= m) {
sum += ax[i];
}
}
sum = sum - m;
suma = suma + sum * sum;
sumb = n - 1 - i;
for (; i >= 0; i--) {
suma = suma + ax[i] * ax[i] * sumb;
}
sumb = sumb * m * m;
long long h = gcd(suma, sumb);
suma /= h;
sumb /= h;
if (sumb == 1||suma==0) {
printf("%lld\n", suma);
}
else printf("%lld/%lld\n", suma, sumb);
}
return 0;
}
D.
据说是FWT 未补
E.
因为你在当前位置放下的A会对之前放下的B和之后放下的B产生贡献,当前放下的B会对之前放下的A和之后放下的A产生贡献,所以就可以按照这种方式进行DP。
你在当前位置能放下A,是因为构成AB的数量不够或者构成BA的数量不够。
你在当前位置能放下B,是因为构成BA的数量不够或者构成AB的数量不够。
按照这种方式递推即可,懒得写递推式了。
#include <iostream>
#include <map>
#include <cstring>
#include <queue>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
#define maxn 10050
const int mod = 1e9 + 7;
long long dp[2200][2200];
int main(void) {
int n, m;
while (scanf("%d%d", &n, &m) != EOF) {
for (int i = 0; i <= n + m; i++) {
for (int z = 0; z <= n + m; z++) {
dp[i][z] = 0;
}
}
dp[0][0] = 1;
for (int i = 0; i <=(n + m); i++) {
for (int z = 0; z <=(n + m); z++) {
if (i < n || i - n < z) {
dp[i + 1][z] += dp[i][z];
dp[i + 1][z] %= mod;
}
if (z < m || z - m < i) {
dp[i][z + 1] += dp[i][z];
dp[i][z + 1] %= mod;
}
}
}
printf("%lld\n", dp[n+m][m+n]);
}
}
F.
在三角形内随机取点,求三角形分割的最大面积的期望。
答案是11/36*S。可以积分求出
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
#include<set>
#include<vector>
#include<map>
#include<cmath>
using namespace std;
typedef long long LL;
double p,s;
int main(void) {
LL x1,y1, x2, y2, x3, y3;
while (cin>>x1>>y1>>x2>>y2>>x3>>y3)
{
LL a=x2-x1,b=y2-y1;
LL c=x3-x1,d=y3-y1;
LL ans=abs(a*d-b*c);
printf("%lld\n", ans*11 );
}
return 0;
}
G.
未补
H.
求序列内的所有集合异或和等于0的集合大小和
看了好多题解,第一次接触线性基,费力理解。
首先集合大小和可以转换为序列中每个元素的参与贡献和。
第一步:我们先求出整个序列的线性基(大小为r),对于线性基外的元素,他们的每个集合的异或和都可以用线性基内的元素表示出来,每个元素参与贡献为2^(n-r-1).总贡献为(n-r)*2^(n-r-1).
第二步:算线性基里面元素的贡献,对于线性基里面的一个数,如果他能被另外n-1个数表示出来,那就证明存在另外一个线性基(线性基大小相等),而它是处于线性基外的元素,贡献也为2^(n-r-1)。依次判断线性基内的每个元素即可。
#include <iostream>
#include <map>
#include <cstring>
#include <queue>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long LL;
#define maxn 100010
const int mod = 1e9 + 7;
struct Linear_Basis{
LL b[63], nb[63], tot;
void init(){
tot = 0;
memset(b, 0, sizeof(b));
memset(nb, 0, sizeof(nb));
}
bool ins(LL x){
for (int i = 62; i >= 0; i--)
if (x&(1LL << i)){
if (!b[i]) { b[i] = x; tot++; break; }
x ^= b[i];
}
return x > 0;
}
LL Max(LL x){
LL res = x;
for (int i = 62; i >= 0; i--)
res = max(res, res^b[i]);
return res;
}
LL Min(LL x){
LL res = x;
for (int i = 0; i <= 62; i++)
if (b[i]) res ^= b[i];
return res;
}
void rebuild(){
for (int i = 62; i >= 0; i--)
for (int j = i - 1; j >= 0; j--)
if (b[i] & (1LL << j)) b[i] ^= b[j];
for (int i = 0; i <= 62; i++)
if (b[i]) nb[tot++] = b[i];
}
LL Kth_Max(LL k){
LL res = 0;
for (int i = 62; i >= 0; i--)
if (k&(1LL << i)) res ^= nb[i];
return res;
}
} LB;
long long pow_mod(long long a, long long n, long long m){
if (n == 0) return 1;
long long x = pow_mod(a, n / 2, m);
long long ans = (long long)x * x % m;
if (n % 2 == 1) ans = ans * a % m;
return ans;
}
LL ax[maxn];
int vis[maxn];
vector<LL>v;
int main(void) {
int n;
Linear_Basis B1, B2, B3;
while(scanf("%d",&n)!=EOF){
v.clear();
B1.init();
B2.init();
B3.init();
for (int i = 0; i < n; i++) {
scanf("%lld", &ax[i]);
vis[i] = 0;
}
int cnt = 0;
LL ans = 0;
for (int i = 0; i < n; i++) {
if (B1.ins(ax[i])) {
vis[i] = 1;
cnt++;
v.push_back(ax[i]);
}
}
ans = (ans + (n-cnt)*pow_mod(2,n-cnt-1,mod)%mod) % mod;
for (int i = 0; i < n; i++) {
if (!vis[i]) {
B2.ins(ax[i]);
}
}
for (int i = 0; i < v.size(); i++) {
B3 = B2;
for (int z = 0; z < v.size(); z++) {
if (i == z) continue;
else {
B3.ins(v[z]);
}
}
if(!B3.ins(v[i]))
ans = (ans + pow_mod(2, n - cnt - 1, mod) % mod) % mod;
}
printf("%lld\n", ans);
}
return 0;
}
I.
队友补的
J.
水
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<string>
#include<iostream>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<stack>
using namespace std;
typedef long long ll;
ll x, y, a, b;
int main()
{
while (scanf("%lld %lld %lld %lld", &x, &a, &y, &b) != EOF)
{
ll fz = b * x - a * y;
ll fm = a * b;
if (fz == 0)
{
printf("=\n");
}
else if (fm > 0 && fz > 0 || fm < 0 && fz < 0)
{
printf(">\n");
}
else
{
printf("<\n");
}
}
return 0;
}