2022NOIPA层联测10
A 异或(xor)
对于任意数,一定有 使得 于是所有下标必然出现过,否则非法
按照二进制递归处理
递归深度即考虑到了最高的哪个二进制位
如果 说明他们该位相同,并且可以选择 ,对应两个数后面的二进制完全相同
于是答案乘 递归一侧
否则,那么一定有 该位为 , 该位为 ,那么如果两侧有同样的下标,就非法,否则递归两边处理
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int read(){
int x = 0; char c = getchar();
while(!isdigit(c))c = getchar();
do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
return x;
}
const int maxn = (1 << 16) + 500;
const int mod = 1e9 + 7;
int n, m, a[maxn];
int ans = 1, tim;
int vis[maxn];
void solve(int l, int r){
if(l >= r || ans == 0)return;
int mid = (l + r) >> 1;
bool fl = 1;
for(int i = l; i <= mid; ++i)if(a[i] != a[mid - l + 1 + i]){fl = 0;break;}
if(fl)ans = (ans + ans) % mod;
else{
++tim;
for(int i = l; i <= mid; ++i)vis[a[i]] = tim;
for(int i = mid + 1; i <= r; ++i)if(vis[a[i]] == tim){ans = 0; return;}
solve(l, mid);
}
solve(mid + 1, r);
}
int main(){
n = read(), m = read();
for(int i = 0; i < (1 << m); ++i)a[i] = read();
for(int i = 0; i < (1 << m); ++i)vis[a[i]] = -1;
for(int i = 1; i <= n; ++i)if(vis[i] == 0){ans = 0;break;}
solve(0, (1 << m) - 1);
printf("%d\n",ans);
return 0;
}
B 图论(graph)
二分答案,每次暴力 能过
我加上了一点小优化变成了 ,没啥大用,反而跑的更慢
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int read(){
int x = 0; char c = getchar();
while(!isdigit(c))c = getchar();
do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
return x;
}
const int maxn = 505;
int mp[maxn][maxn], d0[maxn], d[maxn], np[maxn][maxn], ans;
int n, m;
queue<int>q;
bool vis[maxn];
bool check(int lim){
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= n; ++j)
np[i][j] = mp[i][j];
for(int i = 1; i <= n; ++i)d[i] = d0[i], vis[i] = true;
for(int i = 1; i <= n; ++i)q.push(i);
while(!q.empty()){
int x = q.front(); q.pop();
if(d[x] >= n - 1)continue;
vis[x] = false;
for(int i = 1; i <= n; ++i)if(i != x && np[i][x] == 0 && d[i] + d[x] >= lim){
np[i][x] = np[x][i] = 1; ++d[i]; ++d[x];
if(!vis[i] && d[i] < n - 1)q.push(i), vis[i] = true;
if(!vis[x] && d[x] < n - 1)q.push(x), vis[x] = true;
}
}
// bool fl = 1;
// while(fl){
// fl = 0;
// for(int i = 1; i <= n; ++i)if(d[i] < n - 1)
// for(int j = 1; j <= n; ++j)if(d[j] < n - 1)
// if(i != j && np[i][j] == 0 && d[i] + d[j] >= lim){
// np[i][j] = np[j][i] = 1;
// ++d[i]; ++d[j];
// fl = 1;
// }
// }
for(int i = 1; i <= n; ++i)if(d[i] < n - 1)return false;
return true;
}
int main(){
n = read(); m = read();
for(int i = 1; i <= m; ++i){
int u = read(), v = read();
mp[u][v] = mp[v][u] = 1;
++d0[u]; ++d0[v];
}
int l = 0, r = n + n;
while(l <= r){
int mid = (l + r) >> 1;
if(check(mid))l = mid + 1, ans = mid;
else r = mid - 1;
}
printf("%d\n",ans);
return 0;
}
C 视频(video)
这比某猪国杀难写
预处理操作序列,然后依题意模拟即可
写挂了好多。。
播放与内存不是完全割裂的。你可能为了内存等一段时间再编译。于是完全割裂无法处理
最后借鉴(he)了老殷的优秀写法
存一个每一帧编译完的时间,动态让内存清除元素,外层循环进行播放,妙
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define int long long
int read(){
int x = 0; char c = getchar();
while(!isdigit(c))c = getchar();
do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
return x;
}
const int maxn = 300005;
const ll inf = 1e18;
int n, d, a[maxn], pre[maxn], nxt[maxn], rd[maxn];
char c[maxn];
int id[maxn], p, nd[maxn];
ll tim[maxn];
bool vis[maxn];
bool check(int mid){
int p = mid + 1, size = mid;
for(int i = 1; i <= n; ++i)nd[i] = rd[i], tim[i] = inf;
for(int i = 1; i <= mid; ++i){
tim[id[i]] = 0;
if(pre[id[i]])--nd[pre[id[i]]];
if(nxt[id[i]])--nd[nxt[id[i]]];
}
for(int i = 1; i <= n; ++i){
if(1ll * d * (i - 1) < tim[i])return false;
if(nd[i] == 0)--size;
while(size < mid && p <= n){
if(int v = pre[id[p]]){--nd[v]; if(v <= i && nd[v] == 0)--size;}
if(int v = nxt[id[p]]){--nd[v]; if(v <= i && nd[v] == 0)--size;}
tim[id[p]] = max(d * (i - 1), tim[id[p - 1]]) + a[id[p]];
++size; ++p;
}
}
return true;
}
void in(int i){
if(c[i] == 'B' && !vis[nxt[i]])in(nxt[i]);
id[++p] = i; vis[i] = true;
}
signed main(){
n = read(); d = read();
scanf("%s",c + 1);
for(int i = 1; i <= n; ++i)a[i] = read();
for(int i = 1; i <= n; ++i){
if(c[i] != 'I'){
if(c[i - 1] == 'B') pre[i] = pre[i - 1];
else pre[i] = i - 1;
++rd[pre[i]];
}
}
for(int i = n; i >= 1; --i)if(c[i] == 'B'){
if(c[i + 1] == 'B')nxt[i] = nxt[i + 1];
else nxt[i] = i + 1;
++rd[nxt[i]];
}
for(int i = 1; i <= n; ++i)if(!vis[i])in(i);
int l = 1, r = n, ans = n;
while(l <= r){
int mid = (l + r) >> 1;
if(check(mid))r = mid - 1, ans = mid;
else l = mid + 1;
}
printf("%lld\n",ans);
return 0;
}
D 交换(swap)
考场完全没细想,其实是个水题
把交换的贡献在小数那里计算
考虑一个数移到左侧/右侧,需要交换的次数为左侧/右侧比他大的数,与别的数选择没有任何关系
于是处理一下,取即可
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int read(){
int x = 0; char c = getchar();
while(!isdigit(c))c = getchar();
do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
return x;
}
const int maxn = 500005;
int n, a[maxn], le[maxn], re[maxn];
struct BIT{
int t[maxn];
int lowbit(int x){return x & -x;}
void add(int x){while(x <= n){++t[x];x += lowbit(x);}}
int query(int x){int ans = 0; while(x){ans += t[x]; x -= lowbit(x);}return ans;}
void clear(){for(int i = 1; i <= n; ++i)t[i] = 0;}
}t;
int main(){
n = read();
for(int i = 1; i <= n; ++i)a[i] = read();
for(int i = 1; i <= n; ++i)le[i] = t.query(n) - t.query(a[i]), t.add(a[i]);
t.clear();
for(int i = n; i >= 1; --i)re[i] = t.query(n) - t.query(a[i]), t.add(a[i]);
ll ans = 0;
for(int i = 1; i <= n; ++i)ans += min(le[i], re[i]);
printf("%lld\n",ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】