这场比赛当初是67(?)反正就是Cu滚粗了……

先给个题目的传送门:http://wenku.baidu.com/link?url=mUxdsYomenU-e9SFVPacVtXysemiQA4KnP1EldVuYaB8ECiaLQN4VIAEc19MmHQWyopKLxhzWjWdIE_QrxDWi6PVQt4YuI8IYqPRBN8HUbu

T1

题目大意:给你一个序列,让你分成x段,x∈[A,B],要求每段之和的or和最小,输出最小的or和。A=1时序列长度n<=2000,A>=1时序列长度n<=100

和位运算相关的这类题大多都是按位DP

从高位做到低位,如果该位可以是0,那么就设为0,否则就置1然后随它去

具体实现用dp

如果A=1,直接用dp[i]记录[1,i]区间内,最少分几个块,随便搞搞O(n^2)转移就出来了,如果dp[n]<=B,这位就可以是0,复杂度O(n^2logn)

如果A>1,不能直接记录最少分几个区间,要把切所有刀的可行性都记下来(原谅我的语言表达……),用dp[i][j]表示[1,i]区间能否内分j块,如果有x∈[A,B]使dp[n][x]=1,这位就可以是0,复杂度O(n^3logn)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#define ll long long
#define N 2003
#define INF 2003 using namespace std;
inline int read(){
int ret=0;char ch=getchar();
while (ch<'0' || ch>'9') ch=getchar();
while ('0'<=ch && ch<='9'){
ret=ret*10-48+ch;
ch=getchar();
}
return ret;
} ll bin[60];int K; int n,L,R;
ll s[N]; bool f[105][105];
int dp[N]; int main(){
n=read();L=read();R=read();s[0]=0;
for (int i=1;i<=n;++i) s[i]=s[i-1]+read();
for (bin[K=0]=1;bin[K]<=s[n];++K) bin[K+1]=bin[K]<<1;
--K;
ll ans=0;
if (L==1) for (;K>=0;--K){
memset(dp,127,sizeof(dp));dp[0]=0;
ans=ans<<1;
for (int i=1;i<=n;++i){
for (int pre=0;pre<i;++pre)
if ((((s[i]-s[pre])>>K)|ans)==ans)
dp[i]=min(dp[i],dp[pre]+1);
}
ans^=(ll)(dp[n]>R);
}
else for (;K>=0;--K){
memset(f,0,sizeof(f));f[0][0]=1;
ans=ans<<1;
for (int i=1;i<=n;++i)
for (int j=1;j<=R;++j)
for (int pre=0;pre<i;++pre)
if (f[pre][j-1]&&(((s[i]-s[pre])>>K)|ans)==ans){
f[i][j]=1;break;
}
for (int i=L;i<=R;++i) ans|=(ll)f[n][i];
ans^=1LL;
}
printf("%lld\n",ans);
return 0;
}

 

T2

题目大意:给你一条链,每个点上有狗,每条狗都有一个跳跃力,表示它跳一步能跳过几个节点。现在一条狗要传递消息给另一条狗,只有持有消息的狗才能跳,问所有狗总共最少跳几步。链长狗数均为3*10^4

据说现场暴力出奇迹…………excited

以下是正解

对于跳跃力小于sqrt(n)的狗(我把它叫做小狗),按照跳跃力建立sqrt(n)个类似【轨道】(?)(原谅我形象的比喻……)的东西。每个轨道包含n个点,对应原链的每个节点。对应跳跃力为j的轨道上的点向同轨道左&右边第j个点分别连边,权为1。然后每个轨道上的点都向原链上它对应的点连边,权为0。

对于跳跃力大于sqrt(n)的狗(我把它叫做大狗),暴力简图就行,向所有它跳的到的原链上的点连边,边权为跳的步数。

对于原链上的每个点,向每个初始位置在它上面的狗对应的节点连边,权都为0,如果是大狗,就连到这条狗对应的点,如果是小狗,就连到它跳跃力的轨道上当前点对应的点。总结来说,原链的点,就是用来换狗的。

然后跑dijkstra,边和点都是nlogn的。有个细节就是,边我没有预处理建,我直接在dijkstra里找了,感觉这样会好写一点?

说的有点乱……详见代码吧

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <queue>
#define N 5000006 using namespace std;
inline int read(){
int ret=0;char ch=getchar();
while (ch<'0' || ch>'9') ch=getchar();
while ('0'<=ch && ch<='9'){
ret=ret*10-48+ch;
ch=getchar();
}
return ret;
}
const int K=150; struct edge{
int adj,next;
edge(){}
edge(int _adj,int _next):adj(_adj),next(_next){}
} e[30004];
int n,g[30004],m;
void AddEdge(int u,int v){
e[++m]=edge(v,g[u]);g[u]=m;
} int l,doge;
int id[30004],cnt;
int pos[30004],jump[30004];
int code[30004]; struct HeapNode{
int pos,value;
HeapNode(){}
HeapNode(int _pos,int _value):pos(_pos),value(_value){}
};
inline bool operator >(const HeapNode &x,const HeapNode &y){
return x.value>y.value;
} priority_queue<HeapNode,vector<HeapNode> ,greater<HeapNode> > h;
bool flag[N];
int mind[N];
void dijkstra(int _s,int _t){
memset(mind,127,sizeof(mind));
memset(flag,0,sizeof(flag));
while (!h.empty()) h.pop();
flag[_s]=1;mind[_s]=0;
h.push(HeapNode(_s,0));
while (!flag[_t]&&!h.empty()){
int u=h.top().pos;
h.pop();
flag[u]=1;int nowd=mind[u];
if (u<=l) for (int i=g[u];i;i=e[i].next){
int v=e[i].adj;
if (mind[v]>nowd){
mind[v]=nowd;
h.push(HeapNode(v,mind[v]));
}
}
else if (u>cnt){
u=code[u-cnt];
for (int v=(pos[u]-1)%jump[u]+1;v<=l;v+=jump[u])
if (mind[v]>abs(pos[u]-v)/jump[u]+nowd){
mind[v]=abs(pos[u]-v)/jump[u]+nowd;
h.push(HeapNode(v,mind[v]));
}
}
else{
const int to[3]={(u-1)%l+1,u-(u-1)/l,u+(u-1)/l};
for (int i=0;i<3;++i){
int v=to[i];
if (i&&(u-1)/l!=(v-1)/l) continue;
if (mind[v]>nowd+(i>0)){
mind[v]=nowd+(i>0);
h.push(HeapNode(v,mind[v]));
}
}
} while (!h.empty()&&flag[h.top().pos]) h.pop();
}
if (!flag[_t]) mind[_t]=-1;
} int main(){
l=read();doge=read();
n=cnt=l*(K+1);
memset(g,0,sizeof(g));m=1;
for (int i=1;i<=doge;++i){
pos[i]=read()+1;
if ((jump[i]=read())>K) code[(id[i]=++n)-cnt]=i;
else id[i]=jump[i]*l+pos[i];
AddEdge(pos[i],id[i]);
}
dijkstra(pos[1],pos[2]);
printf("%d\n",mind[pos[2]]);
return 0;
}

  

T3

题目大意:有n个人,每个人有2个房子,有一条河,每个房子都有可能在河任何一边的一个位置。要你建1或2座桥,使得每个人从一个房子到另一个房子(显然不能游泳)的最短距离之和最小,输出最小的和。n<=10^5

当时考场上乱搞一通,连22分算法都想了好久(而且想出来了还无比复杂)……现在看来真是太傻比了。据说此题用各种乱搞的方法也能搞……

首先,对于房子在河的一侧的,读入的时候就能处理掉。所以只需要处理在河2侧的就行了。

对于建1座桥的数据,也就是22分,把所有数丢进去,求个中位数就完了

对于建2座桥的数据,首先我们可以证明,把每个人按2个点的中点从左到右排序,最优解一定是一个前缀走左边的桥,一个后缀走右边的桥。至于具体证明,貌似随便画画图脑补脑补就行了?(虽然想不到TAT)

接下来,问题就变成了,我们需要一个支持插入、删除、求中位数的数据结构,这样什么权值线段树、树状数组上二分、各种STL都能乱搞了

这边顺便安利一下窝的【中根堆】,用4个priority_queue做的(如果不需要删除就只用2个),虽然不开O2很慢,但开了O2速度还是非常可观的。

然后从左往右扫一遍就行了

详见代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <queue>
#define ll long long
#define N 2000006 using namespace std;
inline int read(){
int ret=0;char ch=getchar();
while (ch<'0' || ch>'9') ch=getchar();
while ('0'<=ch && ch<='9'){
ret=ret*10-48+ch;
ch=getchar();
}
return ret;
} int n,op;
int a[N],cnt;
int x[N],y[N];
ll ans; struct MidHeap{
priority_queue<int> l,ld;
priority_queue<int,vector<int> ,greater<int> > r,rd;
int lsize,rsize;ll lsum,rsum;
void clear(){
lsize=rsize=lsum=rsum=0;
while (!l.empty()) l.pop();
while (!r.empty()) r.pop();
while (!ld.empty()) ld.pop();
while (!rd.empty()) rd.pop();
}
void refresh(){
while (l.size() && ld.size() && l.top()==ld.top()){
l.pop();ld.pop();
}
while (r.size() && rd.size() && r.top()==rd.top()){
r.pop();rd.pop();
}
}
void LtoR(){
int tmp=l.top();
--lsize;lsum-=(ll)tmp;l.pop();
++rsize;rsum+=(ll)tmp;r.push(tmp);
}
void RtoL(){
int tmp=r.top();
--rsize;rsum-=(ll)tmp;r.pop();
++lsize;lsum+=(ll)tmp;l.push(tmp);
}
void push(int value){
if (!lsize){
++lsize;lsum+=(ll)value;l.push(value);
return;
}
if (value<=l.top()){
++lsize;lsum+=(ll)value;l.push(value);
if (lsize>rsize+1) LtoR();
refresh();
}
else{
++rsize;rsum+=(ll)value;r.push(value);
if (rsize>lsize) RtoL();
refresh();
}
}
void erase(int value){
if (value<=l.top()){
--lsize;lsum-=(ll)value;ld.push(value);
refresh();
if (lsize<rsize) RtoL();
refresh();
}
else{
--rsize;rsum-=(ll)value;rd.push(value);
refresh();
if (rsize+1<lsize) LtoR();
refresh();
}
}
ll query(){
if (l.empty()) return 0;
ll mid=l.top();
return rsum-lsum+mid*(lsize-rsize);
}
} h0,h1; inline bool cmp(const int &a,const int &b){
return x[a]+y[a]<x[b]+y[b];
} int main(){
op=read();n=read();
cnt=0;ans=0;
if (op==1){
for (int i=1;i<=n;++i){
char c0=getchar();
while (!isalpha(c0)) c0=getchar();
int p0=read();
char c1=getchar();
while (!isalpha(c1)) c1=getchar();
int p1=read();
if (c0!=c1){
a[++cnt]=p0;
a[++cnt]=p1;
++ans;
}
else ans+=(ll)abs(p0-p1);
}
sort(a+1,a+cnt+1);
for (int i=1;i<=cnt;++i) ans+=(ll)abs(a[cnt/2]-a[i]);
}
else{
h0.clear();h1.clear();
for (int i=1;i<=n;++i){
char c0=getchar();
while (!isalpha(c0)) c0=getchar();
int p0=read();
char c1=getchar();
while (!isalpha(c1)) c1=getchar();
int p1=read();
if (c0!=c1){
h1.push(x[++cnt]=p0);
h1.push(y[cnt]=p1);
a[cnt]=cnt;
++ans;
}
else ans+=(ll)abs(p0-p1);
}
sort(a+1,a+cnt+1,cmp);
ll ans0=h1.query();
for (int i=1;i<cnt;++i){
h0.push(x[a[i]]);
h0.push(y[a[i]]);
h1.erase(x[a[i]]);
h1.erase(y[a[i]]);
ll now=h0.query()+h1.query();
if (now<ans0) ans0=now;
}
ans+=ans0;
}
printf("%lld\n",ans);
return 0;
}

  

APIO2015简要题解的更多相关文章

  1. Noip 2014酱油记+简要题解

    好吧,day2T1把d默认为1也是醉了,现在只能期待数据弱然后怒卡一等线吧QAQ Day0 第一次下午出发啊真是不错,才2小时左右就到了233,在车上把sao和fate补掉就到了= = 然后到宾馆之后 ...

  2. Tsinghua 2018 DSA PA2简要题解

    反正没时间写,先把简要题解(嘴巴A题)都给他写了记录一下. upd:任务倒是完成了,我也自闭了. CST2018 2-1 Meteorites: 乘法版的石子合并,堆 + 高精度. 写起来有点烦貌似. ...

  3. Codeforces 863 简要题解

    文章目录 A题 B题 C题 D题 E题 F题 G题 传送门 简要题解?因为最后一题太毒不想写了所以其实是部分题解... A题 传送门 题意简述:给你一个数,问你能不能通过加前导000使其成为一个回文数 ...

  4. HNOI2018简要题解

    HNOI2018简要题解 D1T1 寻宝游戏 题意 某大学每年都会有一次 Mystery Hunt 的活动,玩家需要根据设置的线索解谜,找到宝藏的位置,前一年获胜的队伍可以获得这一年出题的机会. 作为 ...

  5. JXOI2018简要题解

    JXOI2018简要题解 T1 排序问题 题意 九条可怜是一个热爱思考的女孩子. 九条可怜最近正在研究各种排序的性质,她发现了一种很有趣的排序方法: Gobo sort ! Gobo sort 的算法 ...

  6. BJOI2018简要题解

    BJOI2018简要题解 D1T1 二进制 题意 pupil 发现对于一个十进制数,无论怎么将其的数字重新排列,均不影响其是不是 \(3\) 的倍数.他想研究对于二进制,是否也有类似的性质. 于是他生 ...

  7. CQOI2018简要题解

    CQOI2018简要题解 D1T1 破解 D-H 协议 题意 Diffie-Hellman 密钥交换协议是一种简单有效的密钥交换方法.它可以让通讯双方在没有事先约定密钥(密码)的情况下,通过不安全的信 ...

  8. AtCoder ExaWizards 2019 简要题解

    AtCoder ExaWizards 2019 简要题解 Tags:题解 link:https://atcoder.jp/contests/exawizards2019 很水的一场ARC啊,随随便便就 ...

  9. Comet OJ - Contest #2 简要题解

    Comet OJ - Contest #2 简要题解 cometoj A 模拟,复杂度是对数级的. code B 易知\(p\in[l,r]\),且最终的利润关于\(p\)的表达式为\(\frac{( ...

随机推荐

  1. 画图解释 SQL join 语句

    转:http://blog.jobbole.com/40443/ 本文由 伯乐在线 - 奇风余谷 翻译.未经许可,禁止转载!英文出处:Jeff Atwood.欢迎加入翻译组. 我认为 Ligaya T ...

  2. ie6-ie8中不支持opacity透明度的解决方法

    ie6-ie8中是不支持的,需要加上下面这句话:filter: alpha(opacity=70);此外这种效果不能用ietester中的ie6测试,因为ietester的ie6这样写也是不透明的,但 ...

  3. webclient 比浏览器加载页面慢的一个问题

    测试中发现webclient 比浏览器加载页面慢的一个问题:原因WebClient 支持 gzip, deflate,但是未设置 解决方案: class WebClientEx : WebClient ...

  4. Python的高级特性8:你真的了解类,对象,实例,方法吗

    Python的高级特性1-7系列是本人从Python2过渡3时写下的一些个人见解(不敢说一定对),接下来的系列主要会以类级为主. 类,对象,实例,方法是几个面向对象的几个基本概念,其实我觉得很多人并不 ...

  5. 让树莓派开机发送自己的ip到邮箱

    一.代码如下: sendIpMail.py #-*-coding=utf-8-*- import socket import fcntl import struct from email import ...

  6. 主机无法访问虚拟机Linux的apache

    在虚拟机linux里安装了httpd,即appache,启动后,按正常情况在主机是可以用浏览器通过访问虚拟机linux的ip来访问的.如果出现无法访问的情况,解决办法可以参考如下: 这里我的虚拟机联网 ...

  7. 032医疗项目-模块三:药品供应商目录模块——供货商药品目录查询功能----------Service层和Action层和调试

    我们上一篇文章讲了Dao层代码: 这一篇我们讲解Service层和Action层: Service层: 分为接口和实现类,我们主要看实现类:GysemplServiceImpl package yyc ...

  8. usb驱动开发12之设备生命线

    函数usb_control_msg完成一些初始化后调用了usb_internal_control_msg之后就free urb.剩下的活,全部留给usb_internal_control_msg去做了 ...

  9. oracle:db-link使用

    二个oracle instance,如果需要在一个instance上,直接查询另一个instance上的数据,就要用到db-link 创建: create public database link 链 ...

  10. python网络编程学习《一》

    最近,刚实习完,很喜欢实验楼,但是自己的方向仍然不能确定,自己觉得可选择的空间很大,尽管已经是大四的人了,想到别人都在忙着买职业装,买高跟鞋面试,学习化妆什么的,看看自己,反而开始慢慢关注运动,食疗以 ...