luogu7月月赛记录
Posted garen-wang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu7月月赛记录相关的知识,希望对你有一定的参考价值。
luogu7月月赛
A
借助反作弊系统,一些在月赛有抄袭作弊行为的选手被抓出来了!
这道题直接按照题意写出递归即可。写不出来的退役罢(不是我吧)
B
这道题有丶东西
有脑子的都知道思路:每次从第一位到倒数第二位中找出最大的数字,连带后面的数字一起取出,这样取\(\fracn2\)次就一定是最大的。
但是怎么实现啊?
因为有频繁的删除,我们不妨使用双向链表。
其实没有必要记录数组中的下标(我错在这里),只需要记录这些编号的左右对应关系即可。这样有个好处,就是你可以\(O(1)\)地访问到那个你要的任意值的龙珠。
初始化下双向链表后,我们从\(n\)枚举到\(1\),如果这个节点后面还有的话就直接用了,接下来就是naive的链表删除环节了。。。
我sbsb在想成询问区间\([1,n-1]\)的最大值并删除两个数,导致想得非常乱还不会。。。
代码很简单:
#include<bits/stdc++.h>
using std::cin;
using std::cout;
using std::endl;
const int maxn = 100005;
int a[maxn], n;
struct Nodes
int val, idx;
Nodes(int val, int idx): val(val), idx(idx)
bool operator < (const Nodes &rhs) const
return val > rhs.val;
;
std::set<Nodes> s;
int left[maxn], right[maxn], first, last;
int main()
cin >> n;
for(int i = 1; i <= n; i++)
cin >> a[i];
s.insert(Nodes(a[i], i));
if(i > 1) left[i] = i - 1;
if(i < n) right[i] = i + 1;
first = 1; last = n;
for(int i = 1; i <= n / 2; i++)
// get
int idx = -1;
std::vector<Nodes> sorry;
for(std::set<Nodes>::iterator it = s.begin(); it != s.end(); it++)
if(it->idx == last) sorry.push_back(*it);
else
idx = it->idx; break;
for(auto it: sorry) s.insert(it);
cout << a[idx] << ' ' << a[right[idx]] << ' ';
s.erase(Nodes(a[idx], idx));
s.erase(Nodes(a[right[idx]], right[idx]));
if(right[idx] == last)
// 右边没有了
if(left[idx] == 0) break;// 左边也没有了
else
// 左边还有
last = left[idx];
right[last] = 0;
else
// 右边还有
if(left[idx] == 0)
// 左边没有了
first = right[right[idx]];
left[first] = 0;
else
// 左边还有
right[left[idx]] = right[right[idx]];
return 0;
C
讲道理我觉得比B好写(前提是当你复习过树状数组求逆序对)
我们当然不用枚举出\(\fracn (n+1)2\)个区间,按照贡献法,设一个逆序对\((a_i,a_j)\),显然它会被算\(i \times (n - j + 1)\)次。
借鉴一下树状数组的思路,它的思路是把数字离散化后按照桶的思想统计数值比它大,还比它早添加的数字个数,因此在树状数组中统一+1。
我们同样是这个思路,枚举前面逆序对的\(a_j\),树状数组加上原来的下标\(i\),每次也是同样的查询,产生的贡献是查询结果乘以\(n -j + 1\)。
注意了,离散化是包括去重的。。。应该只有我这种菜鸡忘了。
这道题居然要用__int128
。。。
代码:
#include<bits/stdc++.h>
#define ll __int128
const ll maxn = 1000005;
ll a[maxn], b[maxn];
ll n;
struct BIT
ll c[maxn];
inline ll lowbit(int x)
return x & -x;
void add(ll i, ll x)
for(; i <= n; i += lowbit(i)) c[i] += x;
ll query(int i)
ll ret = 0;
for(; i; i -= lowbit(i)) ret += c[i];
return ret;
c;
ll read()
ll ans = 0, s = 1;
char ch = getchar();
while(ch > '9' || ch < '0')
if(ch == '-') s = -1;
ch = getchar();
while(ch >= '0' && ch <= '9')
ans = ans * 10 + ch - '0';
ch = getchar();
return s * ans;
void print(ll x)
if(x >= 10) print(x / 10);
putchar((x % 10) + '0');
int main()
ll ans = 0;
n = read();
for(ll i = 1; i <= n; i++)
b[i] = a[i] = read();
std::sort(b + 1, b + n + 1);
ll len = std::unique(b + 1, b + n + 1) - b - 1;
for(ll i = 1; i <= n; i++)
ll pos = std::lower_bound(b + 1, b + len + 1, a[i]) - b;
c.add(pos, i);
ll temp = c.query(n) - c.query(pos);
ans += temp * (n - i + 1ll);
print(ans);
putchar('\n');
return 0;
D
这辈子不可能写压轴题
以上是关于luogu7月月赛记录的主要内容,如果未能解决你的问题,请参考以下文章
bzoj4881 [ Lydsy2017年5月月赛 ] -- 二分图染色+线段树