CF1208
CF1208
打的话貌似能够涨分的样子?
A
水题
B
枚举左端点,看看右端点的最近位置
开一个类似于桶的东西维护一下上一次出现位置
左端点左边就删掉,否则就要将上一次出现的位置删掉
时间复杂度\(O(n^2)\)或者\(O(n^2logn)\)取决于是否离散化
貌似一个log就是二分答案
然后\(O(n)\)check一遍
#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#include<cctype>
#include<vector>
#include<ctime>
#include<map>
#define LL long long
#define pii pair<int,int>
#define mk make_pair
#define fi first
#define se second
using namespace std;
const int N = 2003;
int a[N];
int pre[N];
map <int,int> m;
int n;
inline int read(){
int v = 0,c = 1;char ch = getchar();
while(!isdigit(ch)){
if(ch == '-') c = -1;
ch = getchar();
}
while(isdigit(ch)){
v = v * 10 + ch - 48;
ch = getchar();
}
return v * c;
}
int main(){
int ans = 0x3f3f3f3f;
n = read();
for(int i = 1;i <= n;++i){
a[i] = read();
if(!m[a[i]]) m[a[i]] = i;
else pre[i] = m[a[i]];
m[a[i]] = i;
// printf("%d\n",pre[i]);
}
bool flag = 1;
for(int i = 1;i <= n;++i){
m.clear();
int r = 0;
for(int j = 0;j < i;++j){
if(m[a[j]] == -1) {flag = 0;break;}
m[a[j]] = -1;
}
if(!flag) break;
for(int j = i;j <= n;++j){
if(m[a[j]] == -1) r = max(r,j);
else if(m[a[j]] != 0){
r = max(r,m[a[j]]);
m[a[j]] = j;
}
else m[a[j]] = j;
}
if(r != 0) ans = min(ans,r - i + 1);
else ans = 0;
}
cout << ans;
return 0;
}
听说貌似有\(O(n)\)做法不大会
C
构造题
分成四块考虑,因为题目中保证是\(4\)的倍数
首先,如果没有\(0-n^2-1\)这个限制
这样子肯定符合要求
\(\begin{array}{cccc}{0} & {0} & {1} & {1} \\ {0} & {0} & {1} & {1} \\ {2} & {2} & {3} & {3} \\ {2} & {2} & {3} & {3}\end{array}\)
但是这样肯定不符合题意
那么我们就对于给每一部分编号
把这一部分整体+4
\(\begin{array}{cccc}{0} & {4} & {1} & {5} \\ {8} & {12} & {9} & {13} \\ {2} & {6} & {3} & {7} \\ {10} & {14} & {11} & {15}\end{array}\)
如果没有保证\(n\)是\(4\)的倍数,那么这样构造一定不对,因为每一行都有数出现了奇数次
由于每一行每一列
每个\(4\)的倍数都只被加了两次
异或起来都答案是没有影响的
那么我们照着这样子构造就好了
D
感觉D是个一眼题,CD应该换一下位置的
最右边的\(0\)对应的位置一定是\(1\)
然后把\(1\)的贡献去掉之后,最右边的\(0\)一定是\(2\)
以此类推
线段树搞一搞就好了
#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#include<cctype>
#include<vector>
#include<ctime>
#define LL long long
#define pii pair<int,int>
#define mk make_pair
#define fi first
#define se second
using namespace std;
const int N = 2e5 + 3;
const LL INF = 1e15;
LL dis[N];
int an[N];
int n,root;
inline LL read(){
LL v = 0,c = 1;char ch = getchar();
while(!isdigit(ch)){
if(ch == '-') c = -1;
ch = getchar();
}
while(isdigit(ch)){
v = v * 10 + ch - 48;
ch = getchar();
}
return v * c;
}
struct Tree{
int t;
struct node{
LL maxx;
LL tag;int pos;
int lc,rc;
}a[N << 2];
inline void pushup(int u){
if(a[a[u].lc].maxx < a[a[u].rc].maxx) a[u].maxx = a[a[u].lc].maxx,a[u].pos = a[a[u].lc].pos;
else a[u].maxx = a[a[u].rc].maxx,a[u].pos = a[a[u].rc].pos;
}
inline void pushdown(int u,int l,int r){
if(!a[u].tag) return;
a[a[u].lc].maxx += a[u].tag;
a[a[u].rc].maxx += a[u].tag;
a[a[u].lc].tag += a[u].tag;
a[a[u].rc].tag += a[u].tag;
a[u].tag = 0;
return ;
}
inline void build(int &u,int l,int r){
if(!u) u = ++t;
if(l == r){
a[u].maxx = dis[l];
a[u].pos = l;
return ;
}
int mid = (l + r) >> 1;
build(a[u].lc,l,mid);build(a[u].rc,mid + 1,r);
pushup(u);
}
inline void updata(int u,int l,int r,int ll,int rr,LL w){
if(ll > rr) return;
if(l == ll && r == rr){
a[u].maxx += w;
a[u].tag += w;
return ;
}
pushdown(u,l,r);
int mid = (l + r) >> 1;
if(rr <= mid) updata(a[u].lc,l,mid,ll,rr,w);
else if(ll > mid) updata(a[u].rc,mid + 1,r,ll,rr,w);
else{
updata(a[u].lc,l,mid,ll,mid,w);
updata(a[u].rc,mid + 1,r,mid + 1,rr,w);
}
pushup(u);
}
inline int query(){return a[root].pos;}
}T;
int main(){
n = read();
for(int i = 1;i <= n;++i) dis[i] = read();
T.build(root,1,n);
// cout << "GG" << endl;
for(int i = 1;i <= n;++i){
int x = T.query();
an[x] = i;
T.updata(root,1,n,x + 1,n,-i);
T.updata(root,1,n,x,x,INF);
}
for(int i = 1;i <= n;++i) printf("%d ",an[i]);
return 0;
}
E
当时就硬是没想出来差分的技巧
首先每个位置可以取到的数肯定是
\([x - (w - len),x+(w -len)]\)这个区间的最大值
之后我们分两种情况讨论
首先
当\(len >= w -len\)时
这时候会长成这个样子

我们设\(d = w - len\)表示能够滑动的距离
对于一个位置\(x\)
首先,绿色部分是只能够从左向右取最大值\([x - d,x]\)
红色只能从右向左取最大值\([x,x + d]\)
中间部分呢?这一部分你会发现
这一部分其实可以和红色或者绿色任意一部分合起来算
这个时候注意不要把黄色部分重复计算就好
当\(len < w - len\)时

这个时候,中间的黄色部分的答案,就变成了序列中的最大值和\(0\)取max
因为中间部分是可以取到序列中的任意数
所以我们只需要维护区间最大值,这个东西随便搞搞吧
注意判断越界时要和\(0\)取max,表示可以不选
#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#include<cctype>
#include<vector>
#include<deque>
#include<ctime>
#define LL long long
#define pii pair<int,int>
#define mk make_pair
#define fi first
#define se second
using namespace std;
const int N = 1e6 + 3;
const int INF = 2e9;
int n,len,w;
int f[21][N];
LL ans[N];
int lg[N];
inline int read(){
int v = 0,c = 1;char ch = getchar();
while(!isdigit(ch)){
if(ch == '-') c = -1;
ch = getchar();
}
while(isdigit(ch)){
v = v * 10 + ch - 48;
ch = getchar();
}
return v * c;
}
inline void pre(){
for(int j = 1;(1 << j) <= len;++j){
for(int i = 1;i + (1 << j) - 1 <= len;++i)
f[j][i] = max(f[j - 1][i],f[j - 1][i + (1 << (j - 1))]);
}
}
inline int work(int l,int r){
int k = lg[r - l + 1];
return max(f[k][l],f[k][r - (1 << k) + 1]);
}
inline int query(int l,int r){
if(l < 1 || r > len) return max(0,work(max(1,l),min(len,r)));
else return work(l,r);
}
int main(){
lg[1] = 0;
for(int i = 2;i <= 1000000;++i) lg[i] = lg[i >> 1] + 1;
n = read(),w = read();
for(int i = 1;i <= n;++i){
len = read();
for(int j = 1;j <= len;++j) f[0][j] = read();
pre();
for(int i = 1;i <= len;++i){
int k = query(i,i + w - len);
ans[i + w - len] += k;
ans[i + w - len + 1] -= k;
}
for(int i = 1;i <= min(len,w - len);++i){
int k = query(i - w + len,i);
ans[i] += k;
ans[i + 1] -= k;
}
if(len < w - len){
int k = max(0,query(1,len));
ans[len + 1] += k;
ans[w - len + 1] -= k;
}
}
for(int i = 1;i <= w;++i) {ans[i] += ans[i - 1];printf("%lld ",ans[i]);}
return 0;
}
F
神仙题解\(SOS DP\)
题目大意求\((i,j,j)i < j < k\)使得\(a_i | (a_j \&a_i)\)最大
\(n <= 10^6,a_i < 2^{21}\)
考虑从从后向前枚举\(i\)
从高位向低位贪心
设\(dp_x\)表示\(x\)设个二进制集合被多少数完全包含
每次对于一个\(a_i\)
从大到小枚举所有位
如果这个位\(j\)不是\(1\)同时满足当前贪心的结果\(x\),\(x | (1 << j)\)被超过两个数包含(保证\(\&\)完之后有这个数)就将这一位加入贪心的答案
更新完答案之后就把每一位包含\(a_i\)的加入
时间复杂度貌似有点爆炸
但是我们发现如果\(dp_x >=2\)那么直接return
所以每个位置最多被更新两次
均摊是\(2^{21}\)的复杂度
#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#include<cctype>
#include<vector>
#include<ctime>
#define LL long long
#define pii pair<int,int>
#define mk make_pair
#define fi first
#define se second
using namespace std;
const int N = 1e6 + 3;
int a[N];
int cnt[N << 2];
int n;
inline int read(){
int v = 0,c = 1;char ch = getchar();
while(!isdigit(ch)){
if(ch == '-') c = -1;
ch = getchar();
}
while(isdigit(ch)){
v = v * 10 + ch - 48;
ch = getchar();
}
return v * c;
}
int ans = 0;
inline void ins(int x,int d){
if(cnt[x] >= 2) return;
if(d == -1){cnt[x]++;return;}
ins(x,d - 1);
if(x & (1 << d)) ins(x ^ (1 << d),d - 1);
}
inline int query(int x){
int now = 0;
for(int i = 20;i >= 0;--i) if(((x & (1 << i)) == 0) && cnt[now | (1 << i)] >= 2) now |= 1 << i;
return now | x;
}
int main(){
n = read();
for(int i = 1;i <= n;++i) a[i] = read();
for(int i = n;i >= 1;--i){
if(i <= n - 2) ans = max(ans,query(a[i]));
ins(a[i],20);
}
printf("%d\n",ans);
return 0;
}
CF1208的更多相关文章
- CF-1208 C.Magic Grid
题目 大意:构造一个n行n列的矩阵,使得每一行,每一列的异或和都相等,n是4的倍数. 先看4*4的矩阵,我们很容易构造出符合要求的矩阵,比如 0 1 2 3 4 5 6 ...
- CF1208题解
C \(\begin{aligned}\ 0 0 1 1\\ 0 0 1 1\\ 2 2 3 3\\ 2 2 3 3\\ \end{aligned}\)将每个四方格分别加上\(0,4,8,12\) D ...
- CF1208 Red Blue Tree
题目链接 问题分析 这是蒟蒻第一道3500!不过话说luogu上两个题解的程序都是假的可还行(2019.11.1)-- 为了方便叙述,下面我们约定 : \([c]\) 的值为 \(1\) 当且仅当 \ ...
- cf1208 E Let Them Slide(差分+RMQ\单调队列)
题意 如题目的图所示,每行都可以左右移动,但是数字不允许断开,且不许越界(宽度为w). 单独求每一列的最大的和为多少. 思路 对于每一列来说,在每一行上都有一个可以取到的区间, 所以,对于一列来说,答 ...
- cf1208 D Restore Permutation (二分+树状数组)
题意 让你构造一个长度为n的序列,记为p1……pn,(这个序列是1~n的全排列的一种) 给你n个数,记为s1……sn,si的值为p1……pi-1中小于pi的数的和. 思路 显然,应该倒着来,也就是从p ...
随机推荐
- bzoj1231 混乱的奶牛
Description 混乱的奶牛 [Don Piele, 2007] Farmer John的N(4 <= N <= 16)头奶牛中的每一头都有一个唯一的编号S_i (1 <= S ...
- KiCad 安装后没有元件怎么办?
KiCad 安装后没有元件怎么办? 按以下步骤试试. 卸载 KiCad EDA. 按 Win+R 输入 %appdata%/kicad 进入 KiCad 的配置目录. 将里面的内容打包成一个 zip ...
- python 异常处理与流程控制
- React 从零搭建项目 使用 create-react-app脚手架
一.安装 npm install -g create-react-app 版本校验:create-react-app --version 二.创建项目 create-react-app指令默认调用np ...
- lavarel box 地址
https://atlas.hashicorp.com/laravel/boxes/homestead download URL https://atlas.hashicorp.com/laravel ...
- WPF 2048游戏的实现
原文:WPF 2048游戏的实现 前几天空闲的时候,实现了一个2048游戏.除了可以设置行数和列数之外,支持修改显示名称,比如下面,改成神雕侠侣中的角色名称: 游戏 ...
- laravel 随笔
laravel5.5 1.laravel 查询数据库默认返回对象,如何改成 返回值为数组 答:在 App\Providers\EventServiceProvider 文件中 第一步: use Il ...
- 阿里云DataWorks正式推出Stream Studio:为用户提供大数据实时计算的数据中台
5月15日 阿里云DataWorks正式推出Stream Studio,正式为用户提供大数据的实时计算能力,同时标志着DataWorks成为离线.实时双计算领域的数据中台. 据介绍,Stream St ...
- Linux 运算符
布尔运算符 下表列出了常用的布尔运算符,假定变量a为10 变量b为20: 运算符 说明 举例 ! 非运算 , 表达式为true 则返回false 否则返回true [!false] 返回true. ...
- pytorch学习笔记(十二):详解 Module 类
Module 是 pytorch 提供的一个基类,每次我们要 搭建 自己的神经网络的时候都要继承这个类,继承这个类会使得我们 搭建网络的过程变得异常简单. 本文主要关注 Module 类的内部是怎么样 ...