JOI 2018 Final 题解
题目列表:https://loj.ac/problems/search?keyword=JOI+2018+Final
T1 寒冬暖炉
贪心
暴力考虑每相邻两个人之间的间隔,从小到大选取即可
#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<vector>
#include<queue>
#include<map>
using namespace std;
const int maxd=1000000007,N=100000;
const double pi=acos(-1.0);
typedef long long ll;
int n,k,a[100100],x[100100];
int read()
{
int x=0,f=1;char ch=getchar();
while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
return x*f;
}
bool cmp(int x,int y)
{
return x>y;
}
int main()
{
n=read();k=read();
int i;
for (i=1;i<=n;i++) a[i]=read();
if (k>=n) {printf("%d",n);return 0;}
for (i=1;i<n;i++) x[i]=(a[i+1]-a[i]-1);
sort(x+1,x+n);
int ans=n;
for (i=1;i<=n-k;i++) ans+=x[i];
printf("%d",ans);
return 0;
}
T2 美术展览
贪心
在确定了\(A_{min}\)和\(A_{max}\)之后,我们显然会选取它们中间的所有数
将所有的美术品按照\(A\)为主关键字排序
将原式改为前缀和的形式
\]
枚举\(r\),同时维护\(A_l-S_{l-1}\)的最大值即可
#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<vector>
#include<queue>
#include<map>
using namespace std;
const int maxd=1000000007,N=100000;
const double pi=acos(-1.0);
typedef long long ll;
struct node{
ll a,b;
}x[500100];
int n;
bool operator <(node p,node q)
{
return p.a<q.a;
}
ll read()
{
ll x=0,f=1;char ch=getchar();
while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
return x*f;
}
int main()
{
int i;
n=read();
for (i=1;i<=n;i++) {x[i].a=read();x[i].b=read();}
sort(x+1,x+1+n);
ll sum=0,pre=0,ans=0;
for (i=1;i<=n;i++)
{
pre=max(pre,-sum+x[i].a);
sum+=x[i].b;
ans=max(ans,pre+sum-x[i].a);
}
printf("%lld",ans);
return 0;
}
T3 团子制作
dp
我们考虑在团子的中心点统计答案
由于中心点不在同一条对角线上的团子不可能重合,于是按照对角线dp
每一次考虑当前的团子是不放/横放/竖放
你看这个dp连数组都不用开
#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<vector>
#include<queue>
#include<map>
using namespace std;
const int maxd=1000000007,N=100000;
const double pi=acos(-1.0);
typedef long long ll;
int n,m;
char s[3010][3010];
int read()
{
int x=0,f=1;char ch=getchar();
while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
return x*f;
}
int getr(int x,int y)
{
if (y-2<=0) return 0;
//cout << "now: " << x << " " << y << endl;
return ((s[x][y-1]=='R') && (s[x][y]=='G') && (s[x][y+1]=='W'));
}
int getC(int x,int y)
{
if (x-2<=0) return 0;
return ((s[x-1][y]=='R') && (s[x][y]=='G') && (s[x+1][y]=='W'));
}
int main()
{
n=read();m=read();
int i,j,k,ans=0;
for (i=1;i<=n;i++) scanf("%s",s[i]+1);
for (k=2;k<=n+m;k++)
{
int nx=min(k-1,n),ny=k-nx;
int pre0=0,pre1=0,pre2=0;
while ((nx>=1) && (ny<=m))
{
//cout << nx << " " << ny << endl;
int r=getr(nx,ny),c=getC(nx,ny);
int tmp=pre0;
//cout << r << " " << c <<endl;
pre0=max(pre0,max(pre1,pre2));
if (r) pre1=max(tmp,pre1)+1;
if (c) pre2=max(tmp,pre2)+1;
//cout << pre0 << " " << pre1 << " " << pre2 << endl;
nx--;ny++;
}
//cout << endl;
ans+=max(max(pre0,pre1),pre2);
}
printf("%d",ans);
return 0;
}
T4 月票购买
图论+DAG dp
贪心的考虑,\(s->t\)和\(u->v\)的路径如果要重合的话就一定会重合连续的一段
我们将\(s->t\)的所有最短路径拎出来并且按照\(s->t\)的方向定向,那么这一定是一个DAG
我们假设两条路径重合的是\(x->y\),那么我们就是求\(dis(u,x)+dis(y,v)\)的最小值
直接在DAG上跑即可,类似于tree dp
#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<vector>
#include<queue>
#include<map>
using namespace std;
typedef long long ll;
const ll maxd=(ll)1e18+7,N=100000;
const double pi=acos(-1.0);
struct node{
int to,nxt,cost;
}sq[400400];
struct heapnode{
int u;ll dis;
};
bool operator <(const heapnode &p,const heapnode &q)
{
return p.dis>q.dis;
}
priority_queue<heapnode> q;
int n,m,s,t,from,to,all=0,head[100100];
ll dis_s[100100],dis_t[100100],dis_u[100100],dis_v[100100],
mind_u[100100],mind_v[100100];
bool vis[100100];
int read()
{
int x=0,f=1;char ch=getchar();
while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
return x*f;
}
void add(int u,int v,int w)
{
all++;sq[all].to=v;sq[all].cost=w;sq[all].nxt=head[u];head[u]=all;
}
void dijkstra(int s,ll *dis)
{
int i;
for (i=1;i<=n;i++) dis[i]=maxd;
memset(vis,0,sizeof(vis));
dis[s]=0;q.push((heapnode){s,0});
while (!q.empty())
{
heapnode now=q.top();q.pop();
if (vis[now.u]) continue;
vis[now.u]=1;int u=now.u;
for (i=head[u];i;i=sq[i].nxt)
{
int v=sq[i].to;
if (dis[v]>dis[u]+sq[i].cost)
{
//cout << v << " ";
dis[v]=dis[u]+sq[i].cost;
q.push((heapnode){v,dis[v]});
}
}
}
}
void init()
{
n=read();m=read();
s=read();t=read();from=read();to=read();
int i;
for (i=1;i<=m;i++)
{
int u=read(),v=read(),w=read();
add(u,v,w);add(v,u,w);
}
dijkstra(s,dis_s);
dijkstra(t,dis_t);
dijkstra(from,dis_u);
dijkstra(to,dis_v);
//for (i=1;i<=n;i++) cout << dis_v[i] << " ";cout << endl;
}
void dfs(int u)
{
vis[u]=1;
int i;
mind_u[u]=dis_u[u];
mind_v[u]=dis_v[u];
for (i=head[u];i;i=sq[i].nxt)
{
int v=sq[i].to;
if (dis_s[u]+dis_t[v]+sq[i].cost==dis_s[t])
{
if (!vis[v]) dfs(v);
if (mind_u[u]+mind_v[u]>min(mind_u[v],dis_u[u])+min(mind_v[v],dis_v[u]))
{
mind_u[u]=min(mind_u[v],dis_u[u]);
mind_v[u]=min(mind_v[v],dis_v[u]);
}
}
}
}
void work()
{
memset(vis,0,sizeof(vis));
dfs(s);
printf("%lld",min(dis_u[to],mind_u[s]+mind_v[s]));
}
signed main()
{
init();
work();
return 0;
}
T5 毒蛇越狱
最暴力的想法就是枚举?的取值,时间复杂度\(O(2^{cnt_?})\),明显爆炸
然后发现可以对所有0的位置或所有1的位置进行容斥,时间复杂度\(O(2^{cnt_0})\)或\(O(2^{cnt_1})\),依然无法保证
然后我们注意到\(L\leq 20\)
由于抽屉原理我们知道\(min(cnt_?,cnt_0,cnt_1)\leq 6\)
于是复杂度瞬间有了保证
具体容斥过程可以看程序头部的注释
//sum[0][i]表示当i中的1恒定为1,剩下的位可0可1时的w之和
//sum[1][i]表示当i中的0恒定为0,剩下的位可0可1时的w之和
//考虑容斥
//当0的个数小于6时,总数为sum[0][p1],但是这样的话某些该为0的位上就是1,枚举p0子集,依照0变为1的个数容斥
//当1的个数小于6时,总数为sum[1][p2|p1],但是这样的话某些该为1的位上就是0,枚举p1子集,依照当前状态与p1的差容斥
#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<vector>
#include<queue>
#include<map>
using namespace std;
const int maxd=1000000007,N=100000;
const double pi=acos(-1.0);
typedef long long ll;
int l,q,n,cnt[1100000],sum[2][1100000],w[1100000];
char s[1100000];
int read()
{
int x=0,f=1;char ch=getchar();
while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
return x*f;
}
int main()
{
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
l=read();q=read();
memset(sum,0,sizeof(sum));
scanf("%s",s);n=(1<<l);
int i,j;
for (i=0;i<n;i++)
{
w[i]=s[i]-'0';sum[0][i]=w[i];sum[1][i]=w[i];
}
for (i=0;i<l;i++)
{
for (j=0;j<n;j++)
{
if (j&(1<<i)) {sum[0][j^(1<<i)]+=sum[0][j];sum[1][j]+=sum[1][j^(1<<i)];}
}
}
for (i=1;i<n;i++) cnt[i]=cnt[i>>1]+(i&1);
while (q--)
{
scanf("%s",s);
int p0=0,p1=0,p2=0;
for (i=0;i<l;i++)
{
if (s[l-i-1]=='0') p0+=(1<<i);
else if (s[l-i-1]=='1') p1+=(1<<i);
else p2+=(1<<i);
}
//cout << p0 << " " << p1 << " " << p2 << endl;
ll ans=0;
if (cnt[p0]<=6)
{
for (i=p0;;i=(i-1)&p0)
{
if (cnt[i]&1) ans-=sum[0][i|p1];
else ans+=sum[0][i|p1];
if (!i) break;
}
}
else if (cnt[p1]<=6)
{
for (i=p1;;i=(i-1)&p1)
{
if (cnt[i^p1]&1) ans-=sum[1][i|p2];
else ans+=sum[1][i|p2];
if (!i) break;
}
}
else if (cnt[p2]<=6)
{
for (i=p2;;i=(i-1)&p2)
{
ans+=w[i|p1];
if (!i) break;
}
}
printf("%lld\n",ans);
}
return 0;
}
JOI 2018 Final 题解的更多相关文章
- LOJ#2351. 「JOI 2018 Final」毒蛇越狱
LOJ#2351. 「JOI 2018 Final」毒蛇越狱 https://loj.ac/problem/2351 分析: 首先有\(2^{|?|}\)的暴力非常好做. 观察到\(min(|1|,| ...
- Codeforces Round #505 (rated, Div. 1 + Div. 2, based on VK Cup 2018 Final) 题解
真心简单的一场比赛 就是坑比较多(自己太蠢) A是一个水题 3分钟的时候过了 B也是一个比较简单的题 类似的套路见得多了 但是我当时可能比较困 想了一会才想出来 19分钟的时候过掉了 C同样很显然 性 ...
- JOI 2020 Final 题解
T1. 只不过是长的领带 大水题,把 \(a_i,b_i\) 从小到大排序. 发现最优方案只可能是大的 \(a_i\) 跟大的 \(b_i\) 匹配,小的 \(a_i\) 与小的 \(b_i\) 匹配 ...
- 【题解】LOJ2759. 「JOI 2014 Final」飞天鼠(最短路)
[题解]LOJ2759. 「JOI 2014 Final」飞天鼠(最短路) 考虑最终答案的构成,一定是由很多飞行+一些上升+一些下降构成. 由于在任何一个点上升或者下降代价是一样的,所以: 对于上升操 ...
- Lyft Level 5 Challenge 2018 - Final Round (Open Div. 2) (前三题题解)
这场比赛好毒瘤哇,看第四题好像是中国人出的,怕不是dllxl出的. 第四道什么鬼,互动题不说,花了四十五分钟看懂题目,都想砸电脑了.然后发现不会,互动题从来没做过. 不过这次新号上蓝名了(我才不告诉你 ...
- 「JOI 2017 Final」JOIOI 王国
「JOI 2017 Final」JOIOI 王国 题目描述 题目译自 JOI 2017 Final T3「 JOIOI 王国 / The Kingdom of JOIOI」 JOIOI 王国是一个 H ...
- 「JOI 2015 Final」分蛋糕 2
「JOI 2015 Final」分蛋糕 2 题解 这道题让我想起了新年趣事之红包这道DP题,这道题和那道题推出来之后的做法是一样的. 我们可以定义dp[i][len][1] 表示从第i块逆时针数len ...
- [LOJ3014][JOI 2019 Final]独特的城市——树的直径+长链剖分
题目链接: [JOI 2019 Final]独特的城市 对于每个点,它的答案最大就是与它距离最远的点的距离. 而如果与它距离为$x$的点有大于等于两个,那么与它距离小于等于$x$的点都不会被计入答案. ...
- Yandex.Algorithm 2018, final round
Yandex.Algorithm 2018, final round A Smart Vending B LIS vs. LDS C Eat And Walk D Search Engine E Gu ...
随机推荐
- logstash采集与清洗数据到elasticsearch案例实战
原文地址:https://www.2cto.com/kf/201610/560348.html Logstash的使用 logstash支持把配置写入文件 xxx.conf,然后通过读取配置文件来采集 ...
- 小P的秘籍
题目描述 小P马上就要来到程序设计大赛的现场.上了,他希望能够AK这次比赛,所以他找到了一个字符串. 这个字符串长度为n,由A和K组成.这个字符串被小p称为AK串.小P任意截取一个区间s,使得这个区间 ...
- vue组件化开发组件拆分原则是什么
原则:可复用.可组合: 两大类:页面组件.功能组件: 除了公共头导航.侧导航.脚部内容,还有:
- Linux下php安装redis扩展(redis已经安装)
1. 下载需要的php操作redis的扩展包 (1).切换到 cd /usr/local/src (2). wget https://github.com/nicolasff/phpredis ...
- Highgo 瀚高数据库的简单搭建以及处理参数等.
1. 获取一个瀚高数据库的安装文件 我这边只获取了 瀚高的 2.0.4 的windows x64 版本的. 来源: 同事从供应商那里获取的. 2. windows上面简单安装 很简单 exe 一路ne ...
- Notepad++的一个用法 转换为unix 格式的文件
1. 跟昨天的linux 下面无法执行脚本的blog 一样 今天发现 notepad++ 有一个功能如下图: 双击 就能够选择文件的类型.. 转换为 unix 格式 就可以 在linux 下面执行了. ...
- SOAP-ERROR: Encoding: string … is not a valid utf-8 string
今天遇到一个错误,看标题就知道是什么错误了.... 最坑爹的是,不是所有的用户会报这个错误.只有少部分.在生产环境又没办法调试. 找了半天都不知道什么原因,字面意思大概是需要一个utf8编码的字符串, ...
- Partition算法以及其应用详解下(Golang实现)
接前文,除了广泛使用在快速排序中.Partition算法还可以很容易的实现在无序序列中使用O(n)的时间复杂度查找kth(第k大(小)的数). 同样根据二分的思想,每完成一次Partition我们可以 ...
- django学习自修第一天【简介】
1. MVC框架 MVC框架的核心思想是解耦,降低各功能之间的耦合性,方便重构代码 (1)低耦合,高内聚 (2)高可扩展性 (3)向后兼容 2. MVT框架 V(视图):核心处理,接受请求,调用模型获 ...
- IBM rational rose画时序图软件破解安装
上边这个链接是开头的安装步骤,照着链接中的步骤安装完之后,接下来看下边. 1.然后安装完成打开软件“IBM Rational License Keyadministrator”.出现下图:选中第二项“ ...