[jzoj NOIP2018模拟10.29]
OI生涯的最高分,来了纪中这么多天,在经历了这么多场“NOIP难度”的模拟赛之后,终于看到了真正的NOIP
今天考场上效率很高,很快码完了全部的题目,留下了足够的时间对拍和...发呆。不得不说看着电脑页面上看着三个bat心里还是很有成就感的,对拍过的代码自然而然分就高了
没有犯什么小错误,数组越界变量写错什么的都没有,只有T3代码出现了一丝纰漏但也通过对拍查到了错。这告诉我们,对拍是很重要的,与其去追求没有把握的正解不如踏踏实实拿到可以拿的分数
T1:列队
题目链接:
https://jzoj.net/senior/#contest/show/2543/0
题目:
Sylvia是一个热爱学习的女孩子。
在平时的练习中,他总是能考到std以上的成绩,前段时间,他参加了一场练习赛,众所周知,机房是一个 的方阵。这天,他又打爆了std,感到十分无聊,便想要hack机房内同学的程序,他会挑选一整行或一整列的同学进行hack ( 而且每行每列只会hack一次 ),然而有些同学不是那么好惹,如果你hack了他两次,他会私下寻求解决,Sylvia十分害怕,只会hack他们一次。假设Sylvia的水平十分高超,每次hack都能成功,求他最 多能hack多少次?
题解:
发现特殊的同学要么从所在行被hack,要么从所在列被hack
每一行看成一个点,每一列看成一个点
棋盘是一个很显然的二分图模型,把不能共存的行和列连边显然得到的是二分图。那么问题:一共最多取出多少行和列就转化为二分图上最大独立集问题
二分图的最大独立集
定义:选出一些顶点使得这些顶点两两不相邻,则这些点构成的集合称为独立集。找出一个包含顶点数最多的独立集称为最大独立集。
方法:最大独立集=所有顶点数-最小顶点覆盖
跑一遍匈牙利或者网络流就是了
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<iostream>
using namespace std; const int N=4e3+;
int n,X,tot;
int match[N],head[N],vis[N];
struct EDGE{
int to,nxt;
}edge[N];
inline int read(){
char ch=getchar();int s=,f=;
while (ch<''||ch>'') {if (ch=='-') f=-;ch=getchar();}
while (ch>=''&&ch<='') {s=(s<<)+(s<<)+ch-'';ch=getchar();}
return s*f;
}
void link(int u,int v){
edge[++tot]=(EDGE){v,head[u]};
head[u]=tot;
}
bool dfs(int x)
{
for (int i=head[x];i;i=edge[i].nxt){
int y=edge[i].to;
if (vis[y]) continue;
vis[y]=;
if (!match[y]||dfs(match[y]))
{
match[y]=x;
return ;
}
}
return ;
}
int main()
{
freopen("phalanx.in","r",stdin);
freopen("phalanx.out","w",stdout);
n=read();X=read();
for (int i=,x,y;i<=X;i++)
{
x=read();y=read();
link(x,y);
}
int ans=;
for (int i=;i<=n;i++)
{
memset(vis,,sizeof(vis));
if (dfs(i)) ++ans;
}
printf("%d\n",(*n-ans)*n);
return ;
}
T2:小凯学数学
题目链接:
https://jzoj.net/senior/#contest/show/2543/1
题目:
由于小凯上次在找零问题上的疑惑,给大家在考场上带来了很大的麻烦,他决心好好学习数学
本次他挑选了位运算专题进行研究 他发明了一种叫做“小凯运算”的运算符:
a$b =( (a&b) + (a|b) )>>1
他为了练习,写了n个数在黑板上(记为a[i]) 并对任意相邻两个数进行“小凯运算”,把两数擦去,把结果留下 这样操作n-1次之后就只剩了1个数,求这个数可能是什么?
将答案从小到大顺序输出
0<=a[i]<=7
题解:
发现a数组无论如何运算结果都是在$[0,7]$这个区间里的
于是我们定义$dp_{l,r}$表示区间$[l,r]$可以合并成的数,考虑到取值范围很小,我们可以用二进制状压起来
发现暴力转移的时间复杂度是$O(64n^3)$的,考场上笔者认为跑不过去
其实可以预处理从两个二进制数合并得到的新的二进制数,这样优化到了$O(n^3)$
大水
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<iostream>
using namespace std; const int N=+;
const int M=<<;
int n;
int a[N],dp[N][N],tmp[M][M];
int merge(int x,int y)
{
int re=;
for (int i=;i<=;i++)
if (x&(<<i))
{
for (int j=;j<=;j++)
if (y&(<<j))
{
int p=(i+j)/;
re|=<<p;
}
}
return re;
}
void init()
{
for (int i=;i<M;i++)
for (int j=;j<M;j++)
tmp[i][j]=merge(i,j);
}
int main()
{
freopen("math.in","r",stdin);
freopen("math.out","w",stdout);
init();
scanf("%d",&n);
for (int i=;i<=n;i++) scanf("%d",a+i),dp[i][i]=<<a[i];
for (int len=;len<=n;len++)
{
for (int l=;l<=n;l++)
{
int r=l+len-;
if (r>n) continue;
for (int k=l;k<r;k++)
{
dp[l][r]|=tmp[dp[l][k]][dp[k+][r]];
}
}
}
for (int i=;i<=;i++) if (dp[][n]&(<<i)) printf("%d ",i);
return ;
}
T3:逛公园
题目链接:
https://jzoj.net/senior/#contest/show/2543/2
题目:
q次询问,每次给出l,r,要求输出答案
题解:
考虑$O(qn)$怎么做?(这种复杂度在考场上得到了完美的85分)。暴力从 l 循环到 r,每次的起始值都是逛完上个景点的最大值和X0的最大值这样对于每个询问都能 O(n)得出答案
以下内容大部分来自题解
记 $F(i,j,x_0)$表示以初始代价 $x_0$ 依次经过第 $i$ 景点到第 $j$ 景点后的答案 有两个性质:
1.对于 $a>=b,F(i,j,a)>=F(i,j,b)$
2.记 $G(i,j)$为 $F(i,j,inf)$,其中 $inf $是正无穷,$S(i,j)$为 $i$ 到 $j$ 的 $D$ 值之和。 则有 $F(i,j,x0)=min( G(i,j), x0+S(i,j) )$。($G(i,j)$就是一定会在$l$处被卡。这个性质没有严谨的证明,感性理解一下)
推论:对于询问的 $l,r$,如果两个子串都被包含在$[l,r]$中,且有 $G1>=G2 且 S1>=S2$,显然第二个子串是一定不会取到的(由性质二得到)。
那么考虑对于一段区间我们怎么做?首先我们把所有的子区间取出来,按$G$值从小到大排序,维护单调栈去掉一定不会取到的子区间,那么剩下的显然就是$G$值单调递增,$S$值单调递减一个个子区间。由于我们是取min,可以在这段区间上二分(当然三分大概也可以,但好像有点傻),找到那个$G$和$S+x0$最接近的区间就是目标区间
发现这样的复杂度还不如之前的做法,但是我们可以分块
块内的贡献:每块大小$\sqrt{n}$,子串个数就是 $O(n)$个可以把每个子串 的 $G$ 值和 $S$ 值都求出来,根据推论把没用的都扔掉。每次询问给出 $X_0$,最大的点一定中间某处(答案是 min 函数),二分即可得出块内的答案
块间的贡献:一共有 2 种
1. 从当前块开始到后面的某一块结束
2. 从之前的某一块开始到当前块结束
参照暴力的策略,那么我们就可以维护一个 $Y$ 值代表上一个块给 这一个块带来的贡献,同时再维护前缀以及后缀的 $G、S$ 值
利用前缀和 $Y$ 值,我们可以采用和之前块内一样的二分来算出答案
利用后缀我们可以算出这一块给下一块的 $Y$ 值,也有三种情况:
1 从上个 $Y$ 走满整块到下个 $Y$
2 从某个后缀开始
3 直接取 $X_0$
三者的最大值即为 $Y$
对于每次询问,我们散块暴力,整块二分再连接就好了
时间复杂度应该是$O(n\sqrt{n}logn+q\sqrt{n}logn)$
好像只是比暴力好那么一点
我的代码跑的好慢
#include<algorithm>
#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<cmath>
using namespace std; const int N=5e4+;
const int M=+;
const int inf=1e9;
int n,q,blo,tcnt,tp;
int d[N],li[N],belong[N],st[N],ed[N],sumd[N];
int F[M][M][M];
struct node{
int G,S;
}T[N],sta[N];
bool operator < (node a,node b) {return a.G<b.G||(a.G==b.G&&a.S<b.S);}
vector <node> vec[M],pre[M],suf[M];
inline int read(){
char ch=getchar();int s=,f=;
while (ch<''||ch>'') {if (ch=='-') f=-;ch=getchar();}
while (ch>=''&&ch<='') {s=(s<<)+(s<<)+ch-'';ch=getchar();}
return s*f;
}
int G(int l,int r)
{
return F[belong[l]][l-st[belong[l]]][r-st[belong[l]]];
}
int S(int l,int r)
{
return sumd[r]-sumd[l-];
}
void calc(vector <node> &V)
{
//printf("%d\n",T[tcnt].S);
sort(T+,T++tcnt);
tp=;
sta[++tp]=T[];
for (int i=;i<=tcnt;i++)
{
while (tp&&T[i].G>=sta[tp].G&&T[i].S>=sta[tp].S) tp--;
sta[++tp]=T[i];
}
for (int i=;i<=tp;i++) V.push_back(sta[i]);
}
void init(int id)
{
for (int l=st[id];l<=ed[id];l++)
{
int x0=inf;
for (int r=l;r<=ed[id];r++)
{
x0=min(li[r],d[r]+x0);
F[id][l-st[id]][r-st[id]]=x0;
}
}
tcnt=;
for (int l=st[id];l<=ed[id];l++)
for (int r=l;r<=ed[id];r++)
{
T[++tcnt]=(node){G(l,r),S(l,r)};
}
calc(vec[id]);
tcnt=;
for (int r=st[id];r<=ed[id];r++)
{
T[++tcnt]=(node){G(st[id],r),S(st[id],r)};
}
calc(pre[id]);
tcnt=;
for (int l=st[id];l<=ed[id];l++)
{
T[++tcnt]=(node){G(l,ed[id]),S(l,ed[id])};
}
calc(suf[id]);
}
int ef(vector <node> Vec,int x0)
{
int l=,r=Vec.size()-;
while (l+<r)
{
int mid=l+r>>;
if (Vec[mid].G>Vec[mid].S+x0) r=mid;
else l=mid;
}
int re=min(Vec[l].G,Vec[l].S+x0);
re=max(re,min(Vec[r].G,Vec[r].S+x0));
if (l+<Vec.size()-)
{
++l;
re=max(re,min(Vec[l].G,Vec[l].S+x0));
}
return re;
}
void solve(int l,int r,int x0)
{
if (belong[l]==belong[r])
{
int mx=x0,Y=x0;
for (int i=l;i<=r;i++)
{
Y=min(max(Y,x0)+d[i],li[i]);
mx=max(mx,Y);
}
printf("%d\n",mx);
return;
}
int Y=x0,mx=x0;
for (int i=l;i<=ed[belong[l]];i++)
{
Y=min(max(Y,x0)+d[i],li[i]);
mx=max(mx,Y);
}
Y=max(Y,x0);
for (int i=belong[l]+;i<=belong[r]-;i++)
{
mx=max(mx,ef(pre[i],Y));
mx=max(mx,ef(vec[i],x0));
Y=min(G(st[i],ed[i]),Y+S(st[i],ed[i]));//从上个Y走满整块到下个Y
Y=max(Y,ef(suf[i],x0));//从某个后缀开始
Y=max(Y,x0);//直接取X0
}
for (int i=st[belong[r]];i<=r;i++)
{
Y=min(max(Y,x0)+d[i],li[i]);
mx=max(mx,Y);
}
printf("%d\n",mx);
}
int main()
{
freopen("park.in","r",stdin);
freopen("park.out","w",stdout);
n=read();q=read();
for (int i=;i<=n;i++) d[i]=read(),sumd[i]=sumd[i-]+d[i];
for (int i=;i<=n;i++) li[i]=read();
blo=sqrt(n);
for (int i=;i<=n;i++) belong[i]=(i-)/blo+;
for (int i=;i<=belong[n];i++)
{
st[i]=(i-)*blo+;
ed[i]=min(i*blo,n);
init(i);
}
while (q--)
{
int l=read(),r=read(),x0=read();
solve(l,r,x0);
}
return ;
}
[jzoj NOIP2018模拟10.29]的更多相关文章
- [jzoj NOIP2018模拟10.23]
丢分主要是下面几个方面: 1.T2代码交错了,有个特判没写丢了10分 2.T1线段树加等差数列写错了(其实二维差分就可以,但我当时不会) 3.T3思考再三还是为了10分写上了主席树,还是写错了 总体评 ...
- [JZOJ NOIP2018模拟10.21]
考试之前我刚刚领略到了特判的重要性,没想到T2的两个子任务还是写挂了,丢了20分 考试的感觉不行,一路打的都是暴力,正解的思路想到一半就断了推不下去 T1:逛公园 题目链接: https://jzoj ...
- [JZOJ NOIP2018模拟10.20 B组]
T1:原根(math) 题目链接: http://172.16.0.132/senior/#contest/show/2532/0 题目: 题解: 一个数m原根的个数是$\phi{(\phi{(m)} ...
- [JZOJ NOIP2018模拟10.20 A组]
由于T3数据出锅,还不清楚自己的分数...估分150,前100已经拿到了,T3的50没拍过(写的就是暴力怎么拍),感觉很不稳 考试的时候就是特别的困,大概是因为早上在房间里腐败...腐败完了才睡觉 T ...
- [JZOJ NOIP2018模拟10.19]
T1写炸了今天,期望70却落了个20...连链上的都没有写对 T3什么什么线段树分治套AC自动机,表示我完全自闭了,幸好考场上没有杠T3 总体比赛还是比较舒服,暴力分给的蛮足的,不像昨天那样 T1:林 ...
- [jzoj 5926] [NOIP2018模拟10.25] naive 的图 解题报告(kruskal重构树+二维数点)
题目链接: https://jzoj.net/senior/#main/show/5926 题目: 题解: 显然最小的最大路径在最小生成树上(最小生成树=最小瓶颈生成树) 于是我们建出kruskal重 ...
- [JZOJ 5893] [NOIP2018模拟10.4] 括号序列 解题报告 (Hash+栈+map)
题目链接: https://jzoj.net/senior/#main/show/5893 题目: 题解: 考虑暴力怎么做,我们枚举左端点,维护一个栈,依次加入元素,与栈顶元素和栈内第二个元素相同时弹 ...
- [JZOJ 5912] [NOIP2018模拟10.18] VanUSee 解题报告 (KMP+博弈)
题目链接: https://jzoj.net/senior/#contest/show/2530/2 题目: 众所周知,cqf童鞋对哲学有着深入的理解和认识,并常常将哲学思想应用在实际生活中,例如锻炼 ...
- [JZOJ 5910] [NOIP2018模拟10.18] DuLiu 解题报告 (并查集+思维)
题目链接: https://jzoj.net/senior/#contest/show/2530/0 题目: LF是毒瘤出题人中AK IOI2019,不屑于参加NOI的唯一的人.他对人说话,总是满口垃 ...
随机推荐
- 0x28 IDA*
一个早上做完了我真牛B 就是A*用于DFS啊,现在我才发现迭代加深真是个好东西. poj3460 %了%了我们的目标是把它的顺序变对,那么第i个位置的值+1是要等于第i+1个位置的值的.对于一个操作, ...
- poj--1383--Labyrinth(树的直径)
Labyrinth Time Limit: 2000MS Memory Limit: 32768K Total Submissions: 4062 Accepted: 1529 Descrip ...
- git提交不用每次都输入用户名密码
克隆项目二种方式: 1. 使用https url克隆, 复制https url 然后到 git clone https-url 2.使用 SSH url 克隆却需要在克隆之前先配置和添加好 SSH ...
- sql:String格式转换为时间进行比较
字符串的格式为 yyyy-MM-dd HH:mm:ss str_to_date(a.time, '%Y-%m-%d %k:%i') < str_to_date(b.time, '%Y-%m-%d ...
- Codeforces 993C. Careful Maneuvering(详细注解)
解题思路 -100和+100是没有用的,只要知道左边的飞船轴和右边的飞船轴离y轴一样近即可.为简单起见,我们将左边的轴设为-1,右边的设为1. 某个点能摧毁的飞船一定是因为有两个飞船关于这个点对称.即 ...
- SQLAlchemy tutorial
SQLAlchemy tutorial 重要概念 ORM:数据库对象 <--> class --> 类实例instance 定义数据库连接 session:数据库事务通过sessio ...
- APUE学习笔记7——进程间通信
1 管道 管道一般是一种半双工的进程间通信方式,只能够在具有公共祖先的进程之间使用,比如一个管道由一个进程创建,然后该进程调用fork,之后父.子进程就可以使用该管道. 管道是调用pipe函数创建的. ...
- ZBrush中SnakeHook蛇钩笔刷介绍
不同笔刷用着不同的作用,绘画出来的效果也是千姿百态,各有千秋,有些笔刷在使用的时候可以替代,但有些笔刷是无法替代,不可超越的,比如ZBrush®中给我们提供的,SnakeHook笔刷,该笔刷在模型表面 ...
- ZBrush软件特性之Draw
ZBrush®中的Draw绘制调色板包括了当前绘图的修改和控制工具,能改变工具大小.形状.强度.不透明度和其他一些功能. Draw Size(绘制大小):设置画笔的外形尺寸,调节ZBrush绘制笔刷圆 ...
- 移动端和pc端的判断,不同端做不同的处理
1.通过js判段是pc端还是移动端 function browserRedirect() { var type = ""; var sUserAgent = navigator.u ...