题目列表: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\)为主关键字排序

将原式改为前缀和的形式

\[S-(A_{max}-A_{min})=S_r-S_{l-1}-Ar+A_l=(S_r-A_r)+(A_l-S_{l-1})
\]

枚举\(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;
}

最新文章

  1. Web API后端调用接口 (Get,POST,Put,Delete)
  2. java常用IO流数据流小结
  3. 更改Xampp-sql的默认密码-配置appche运行环境
  4. 【leetcode】Two Sum (easy)
  5. LaTeX常用数学符号
  6. 惊魂web应用宕机记一次网站的紧急恢复
  7. php原子操作,文件锁flock,数据库事务
  8. iOS - Threads 多线程
  9. 开始记录blog
  10. MySQL索引的查看创建和删除
  11. JNI(5)The Invocation API
  12. NHibernate之映射文件配置说明(转载2)
  13. AVL树相关操作
  14. java的抽象类和抽象方法(注意查看如何调用抽象类中的非抽象方法)
  15. windows中操作文件和目录的函数
  16. eclipse创建一个文件夹
  17. Vue(day3)
  18. Vue应用请求SpringBoot API出现 CORS 跨域请求设置 Invalid CORS request错误
  19. hibernate坑边闲话2
  20. STL 容器区别:vector、list、deque、set、map的底层实现

热门文章

  1. yosay
  2. openstack-虚拟化模型
  3. java总结:Java中获取系统时间(年、月、日)以及下拉菜单默认选择系统年、月、日的方法
  4. echarts图片保存
  5. php常用方法
  6. [翻译]在asp.net core2.0 OpenID Connect Handler中丢失了声明(CLaims)?
  7. Mac 在terminal 上用命令打开sublime
  8. CSS3 Flexbox轻巧实现元素的水平居中和垂直居中
  9. 运维常用mysql语句
  10. windows 10 &amp; task view &amp; shortcut