A层邀请赛1
A. Race
容易想到树,也容易想到判断两数大小关系在于第一个不同的二进制位
一个重要的点(我没想到):积分相当于排在它前面的人构成的点对数
通过在树上取反向可以得到的做法,然后展开一下式子,或者观察一下二进制数,
展开平方得到一堆
当一个点对存在,其实是这两个二进制位都为特定数,有个数,而平方展开系数为,所以这部分系数为
而平方项显然也是,所以一个简单的树即可
code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 200005;
const int mod = 1e9 + 7;
typedef long long ll;
int n, m, a[maxn], mc;
ll score[maxn],ans;
int tong[30];
struct tire{
int ch[maxn * 31][2], node = 1, ls[33], root = 1, cnt[maxn * 31];
void add(int x){
for(int i = 0; i < m; ++i)ls[i] = (bool) (x & (1 << i));
int now = root;
for(int i = m - 1; i >= 0; --i){
if(!ch[now][ls[i]])ch[now][ls[i]] = ++node;
now = ch[now][ls[i]];
++cnt[now];
}
}
int id, tot;
void dfs(int now, int dep, ll sum, ll ans){
if(dep == 0)score[++id] = ans * (1 << (m - 1)) % mod;
int lc = ch[now][0], rc = ch[now][1];
if(lc)dfs(lc, dep - 1,(sum + cnt[rc]) % mod, (ans + cnt[rc] * (sum + cnt[rc]) % mod) % mod);
if(rc)dfs(rc, dep - 1,(sum + cnt[lc]) % mod, (ans + cnt[lc] * (sum + cnt[lc]) % mod) % mod);
}
}T;
int main(){
scanf("%d%d", &n, &m);mc = (1 << m);
for(int i = 1; i <= n; ++i)scanf("%d", &a[i]);
sort(a + 1, a + n + 1);
for(int i = 1; i <= n; ++i)T.add(a[i]);
T.dfs(1, m, 0, 0);
for(int i = 1; i <= n; ++i)ans = ans xor (score[i] % mod);
for(int i = 1; i <= n; ++i)score[i] = (score[i] + 1ll * (n - i) * (n - i) % mod) % mod;
printf("%lld\n", ans);
return 0;
}
B. 青蛙
这种乱搞贪心题我怎么不敢猜了呢
有一说一,用二分的正解我想到了,但是不觉得正确。。。。。
找出尽可能多条免费道路,记条数为
用最小的挨个跳完全程,其他的直接跳
用最大的个跳免费的,剩余格子显然能免费跳完,剩下的直接跳到
如何找
可以用维护,每次找距离 的最大的那个跳,正确性不会证。。
更优秀的做法是双指针,每次尽可能让左指针跳到右指针,可以发现这样不会使答案更劣,比上面的做法少一个,并且正确性显然
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 55;
int n, m, k, d, c[maxn], a[maxn], f[maxn];
void work(){
scanf("%d%d%d%d", &n, &m, &k, &d);
for(int i = 1; i <= m; ++i)scanf("%d", &c[i]);
for(int i = 1; i <= k; ++i)scanf("%d", &a[i]);
sort(a + 1, a + k + 1); sort(c + 1, c + m + 1);
int p = 1, cnt = 0;
for(int i = 0 ; i <= k ; ++i)f[i] = 0;
for(; p <= k; ++p)if(a[p] - 1 <= d)f[p] = 1;else break;
for(int i = 1; i <= k; ++i)if(f[i] && a[p] - a[i] <= d && p <= k)f[p] = 1, f[i] = 0, ++p;
for(int i = k; i >= 1; --i)if(n - a[i] <= d && f[i]) ++cnt;else break;
ll ans = 0;
if(cnt == 0){
a[0] = 1; a[k + 1] = n;
for(int i = 1; i <= k + 1; ++i)if(a[i] - a[i - 1] > d)ans += c[1];
ans -= c[1];
}
for(int i = 1; i <= m - cnt; ++i)ans = (ans + c[i]);
cerr<< cnt << endl;
printf("%lld\n",ans);
}
signed main(){
int t;scanf("%d",&t);
for(int ask = 1; ask <= t; ++ask)work();
return 0;
}
C. 序列
吉司机线段树板子,对取操作,线段树上维护区间最小值和严格次小值,如果取的数小于最小值,就不用管,大于次小值继续递归,在两个值之间只修改最小值
剩下的就是码了
code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn = 100005;
const ll inf = 0x3f3f3f3f3f3f3f3f;
int n, m, a[maxn],val[maxn];
char c[3];
struct node{ll val; int op;}ans;
struct tree{
struct node{
ll dt, mi, cmi;
int ctmi, ctdt;
}t[maxn << 2 | 1];
void push_up(int x){
int ls = x << 1, rs = x << 1 | 1;
if(t[ls].mi < t[rs].mi){
t[x].mi = t[ls].mi;
t[x].cmi = t[ls].cmi;
t[x].cmi = min(t[x].cmi, t[rs].mi == t[x].mi ? inf : t[rs].mi);
t[x].cmi = min(t[x].cmi, t[rs].cmi == t[x].mi ? inf : t[rs].cmi);
}else{
t[x].mi = t[rs].mi;
t[x].cmi = t[rs].cmi;
t[x].cmi = min(t[x].cmi, t[ls].mi == t[x].mi ? inf : t[ls].mi);
t[x].cmi = min(t[x].cmi, t[ls].cmi == t[x].mi ? inf : t[ls].cmi);
}
}
void built(int x, int l, int r){
if(l == r){t[x].mi = val[l]; t[x].cmi = inf;return;}
int mid = (l + r) >> 1;
built(x << 1, l , mid);
built(x << 1 | 1, mid + 1, r);
push_up(x);
}
void push_down(int x){
int ls = x << 1, rs = x << 1 | 1;
if(t[x].ctdt){
t[ls].ctdt += t[x].ctdt;
t[rs].ctdt += t[x].ctdt;
t[ls].dt += t[x].dt;
t[rs].dt += t[x].dt;
t[ls].mi += t[x].dt;
t[rs].mi += t[x].dt;
t[ls].cmi += t[x].dt;
t[rs].cmi += t[x].dt;
t[x].dt = 0;
t[x].ctdt = 0;
}
if(t[x].ctmi){
if(t[ls].mi < t[x].mi){
t[ls].ctmi += t[x].ctmi;
t[ls].mi = t[x].mi;
}
if(t[rs].mi < t[x].mi){
t[rs].ctmi += t[x].ctmi;
t[rs].mi = t[x].mi;
}
t[x].ctmi = 0;
}
}
void modify_add(int x, int l, int r, int L, int R, int dt){
if(L <= l && r <= R){
t[x].mi += dt;
t[x].cmi += dt;;
t[x].dt += dt;
++t[x].ctdt;
return;
}
push_down(x);
int mid = (l + r) >> 1;
if(L <= mid)modify_add(x << 1, l, mid, L, R, dt);
if(R > mid)modify_add(x << 1 | 1, mid + 1, r, L, R, dt);
push_up(x);
}
void query(int x, int l, int r, int pos){
if(l == r){
ans.val = t[x].mi;
ans.op = t[x].ctmi + t[x].ctdt;
return;
}
push_down(x);
int mid = (l + r) >> 1;
if(pos <= mid)query(x << 1, l, mid, pos);
else query(x << 1 | 1, mid + 1, r, pos);
}
void modify_min(int x, int l, int r, int L, int R, int dt){
if(L <= l && r <= R){
if(t[x].mi >= dt)return;
if(t[x].cmi > dt){
t[x].mi = dt;
++t[x].ctmi;
return;
}
}
push_down(x);
int mid = (l + r) >> 1;
if(L <= mid)modify_min(x << 1, l, mid, L, R, dt);
if(R > mid)modify_min(x << 1 | 1, mid + 1, r, L, R, dt);
push_up(x);
}
}T;
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; ++i)scanf("%d", &val[i]);
T.built(1, 1, n);
scanf("%d", &m);
for(int i = 1; i <= m; ++i){
scanf("%s",c);
if(c[0] == 'Q'){
int pos; scanf("%d", &pos);
T.query(1, 1, n, pos);
printf("%lld %d\n",ans.val, ans.op);
}else{
int l, r, dt;scanf("%d%d%d",&l,&r,&dt);
if(c[0] == 'A' && dt)T.modify_add(1, 1, n, l, r, dt);
if(c[0] == 'M')T.modify_min(1, 1, n, l, r, dt);
}
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】