1. /*
  2. 又是AK局...
  3. hjc又双叒叕AK了...
  4. Hmmm...我侥幸
  5. */

Problem A card

给出无序序列a[]可以选择一个数插入到合适的位置作为一次操作,至少多少次操作后可以把序列变成有序。

对于100%的数据,序列长度 $l\leq5e5$

Solution : 最长上升子序列(LIS)-n

 这个是显然的结论,最优的话一定是保证LIS情况下,把除LIS外的数依次加到有序的LIS里面刚好加了这么多个。

所以答案是n-LIS,最优性显然: LIS保证需要插入的数字数量最少,而需要插入的数字最少只需要1步移动就一定可以保证把数列LIS增加1.

O(n log2 n)复杂度求LIS是这道题的关键。记f[i]表示长度为i的上升子序列末尾元素最大是多少。

显然当i变大的时候f[i]单调不降,有单调性,可以二分优化转移。找到第1个j,$f[j] \leq a[i]$,转移就行。

注意这个需要最大化j才能保证转移最优,所以是upper_bound而不是lower_bound。

  1. # pragma G++ optimize()
  2. # include <iostream>
  3. # include <cstring>
  4. # include <cstdio>
  5. # include <algorithm>
  6. using namespace std;
  7. const int N=1e6+;
  8. int a[N],ans,n,f[N];
  9. inline int read()
  10. {
  11. int X=,w=; char c=;
  12. while(c<''||c>'') {w|=c=='-';c=getchar();}
  13. while(c>=''&&c<='') X=(X<<)+(X<<)+(c^),c=getchar();
  14. return w?-X:X;
  15. }
  16. int main()
  17. {
  18. freopen("card.in","r",stdin);
  19. freopen("card.out","w",stdout);
  20. n=read();
  21. int ans=;
  22. for (int i=;i<=n;i++) a[i]=read();
  23. memset(f,0x3f,sizeof(f));
  24. f[]=a[];
  25. for (int i=;i<=n;i++) {
  26. int p=upper_bound(f,f++n,a[i])-f-;
  27. if (p==-) { f[]=min(f[],a[i]); ans=max(ans,); continue;}
  28. ans=max(ans,p+);
  29. f[p+]=min(f[p+],a[i]);
  30. }
  31. cout<<n-ans<<'\n';
  32. return ;
  33. }

Card.cpp

Problem B pikaqiu

给出n*m的地图每个点可以是石头(1)和路(0),经过路的代价是1,经过石头的代价是5,有起点(5)和终点(9),问起点到终点最小代价是多少,

若代价大于可支付的能量T,输出-1,否则输出剩余能量。

对于100%的数据: $n,m\leq 500$

Solution : 拆点跑Dijkstra最短路,考虑一个点和上下左右四个点有有向连边,若这个点是石头那么建长为5的边否则建长为1的边

然后这个图变成是n2个点,4n2条边的有向图,然后跑Dijkstra,求出[s,t]的最短路即可。(注意一定是单向加边,由于重边会导致本来是石头的边变成路,造成冲突)

-spfa已经死了 -不他没活过

复杂度O(n2 log2 n2)

  1. # pragma G++ optimize()
  2. # include <iostream>
  3. # include <cstring>
  4. # include <algorithm>
  5. # include <cstdio>
  6. # include <queue>
  7. using namespace std;
  8. const int N=1e6+;
  9. const int dx[]={-,,,};
  10. const int dy[]={,,,-};
  11. int T,n,m;
  12. int head[N],d[N],mp[N];
  13. int s,tot=,INF;
  14. bool vis[N];
  15. struct record{
  16. int pre,to,w;
  17. }a[N<<];
  18. # define Num(i,j) (m*(i-)+j)
  19. inline int read()
  20. {
  21. int X=,w=; char c=;
  22. while(c<''||c>'') {w|=c=='-';c=getchar();}
  23. while(c>=''&&c<='') X=(X<<)+(X<<)+(c^),c=getchar();
  24. return w?-X:X;
  25. }
  26. void adde(int u,int v,int w)
  27. {
  28. a[++tot].pre=head[u];
  29. a[tot].to=v;
  30. a[tot].w=w;
  31. head[u]=tot;
  32. }
  33. struct rec{
  34. int id,lenth;
  35. bool operator < (const rec a)const{
  36. if (lenth!=a.lenth) return lenth>a.lenth;
  37. else return id>a.id;
  38. }
  39. };
  40. priority_queue<rec>q;
  41. int dijkstra(int s,int e)
  42. {
  43. memset(vis,false,sizeof(vis));
  44. memset(d,,sizeof(d));INF=d[];d[s]=;
  45. rec Node; Node.id=s; Node.lenth=; q.push(Node);
  46. while (! q.empty()){
  47. rec Node=q.top(); q.pop();
  48. int u=Node.id;
  49. if (vis[u]==true) continue;
  50. vis[u]=true;
  51. for (int i=head[u];i!=;i=a[i].pre){
  52. int v=a[i].to;
  53. if (d[v]-a[i].w>d[u]) {
  54. d[v]=a[i].w+d[u];
  55. rec N; N.id=v;N.lenth=d[v];
  56. q.push(N);
  57. }
  58. }
  59. }
  60. return d[e];
  61. }
  62. int main()
  63. {
  64. freopen("pikaqiu.in","r",stdin);
  65. freopen("pikaqiu.out","w",stdout);
  66. T=read(); n=read(); m=read();
  67. int Str,End;
  68. for (int i=;i<=n;i++)
  69. for (int j=;j<=m;j++) {
  70. int t=Num(i,j);mp[t]=read();
  71. if (mp[t]==) Str=t;
  72. else if (mp[t]==) End=t;
  73. }
  74. for (int i=;i<=n;i++)
  75. for (int j=;j<=m;j++) {
  76. int now=Num(i,j);
  77.  
  78. for (int tp=;tp<;tp++) {
  79. int x=i+dx[tp],y=j+dy[tp];
  80. if (x<||x>n||y<||y>m) continue;
  81. int num=Num(x,y);
  82. if (mp[num]==) adde(now,num,);
  83. else adde(now,num,);
  84. }
  85. }
  86. int Ans=dijkstra(Str,End);
  87. if (Ans>=T) puts("-1");
  88. else cout<<T-Ans<<'\n';
  89. return ;
  90. }

pikaqiu.cpp

Problem C min

一个含有n项的数列a[],求出每一项前面的第m个数到它这个区间内的最小值Mini

对于100%的数据 $n\leq 1e7$

Solution : 

单调队列题目,显然给了60%的线段树的暴力分。考虑O(n)做法。

弄一个双端队列deque然后前面弹出不在范围内的数,后面弹出不优的数和插入一个新的数。

队列维护的是下标单增,值单增的数列,同时保证在范围内,取数时取队头。

luogu 滑动窗口 单调队列裸题。

  1. # pragma G++ optimize()
  2. # include <deque>
  3. # include <iostream>
  4. # include <cstdio>
  5. using namespace std;
  6. const int N=1e6+;
  7. int a[N],n,m;
  8. deque<int>q;
  9. inline int read()
  10. {
  11. int X=,w=; char c=;
  12. while(c<''||c>'') {w|=c=='-';c=getchar();}
  13. while(c>=''&&c<='') X=(X<<)+(X<<)+(c^),c=getchar();
  14. return w?-X:X;
  15. }
  16. void write(int x)
  17. {
  18. if (x<) x=-x,putchar('-');
  19. if (x>) write(x/);
  20. putchar(''+x%);
  21. }
  22. signed main()
  23. {
  24. freopen("min.in","r",stdin);
  25. freopen("min.out","w",stdout);
  26. n=read();m=read();
  27. int Test=;
  28. for (int i=;i<=n;i++) a[i]=read();
  29. for (int i=;i<=n;i++) {
  30. while (!q.empty()&&q.front()<i-m) q.pop_front();
  31. while (!q.empty()&&a[q.back()]>=a[i]) q.pop_back();
  32. q.push_back(i);
  33. write(a[q.front()]);putchar(' ');
  34. }
  35. putchar('\n');
  36. return ;
  37. }

min.cpp

Problem D smrtfun

给出n个数对$(left_i,right_i)$选出若干组,

最大化 $\sum\limits_{i=1}^k left_i + \sum\limits_{i=1}^k right_i$ 且 $ \sum\limits_{i=1}^k left_i \geqslant 0 ,  \sum\limits_{i=1}^k right_i \geqslant  0$

对于100%的数据 $n \leq 100$

Solution: 背包问题,令$f[i][j]$表示前i个数对,$left$求和等于$k$,$right$求和的最大值。

转移比较简单就是  $f[i][j]=max \{ f[i-1][j],f[i-1][j-left_{now}]+right_{now} \} $

答案就是 max{f[n][j]} (0<=j<=INF)

然后初始值比较恶心,f[0][]都是负无穷,然后f[0][0]=0

然而c++没有下标为负数的数组,需要加上基底E=1e5才行,

时间复杂度O(n*mx2)

  1. # pragma G++ optimize()
  2. # include <iostream>
  3. # include <cstdio>
  4. # include <cstring>
  5. # define left Lift
  6. # define right Right
  7. using namespace std;
  8. const int N=,M=1e5+;
  9. const int E=1e5;
  10. const int INF=1e5-;
  11. int f[N][M<<];
  12. int left[N],right[N];
  13. int n,mx,ans;
  14. int max(int x,int y) {return (x>y?x:y);}
  15. inline int read()
  16. {
  17. int X=,w=; char c=;
  18. while(c<''||c>'') {w|=c=='-';c=getchar();}
  19. while(c>=''&&c<='') X=(X<<)+(X<<)+(c^),c=getchar();
  20. return w?-X:X;
  21. }
  22. int main()
  23. {
  24. freopen("smrtfun.in","r",stdin);
  25. freopen("smrtfun.out","w",stdout);
  26. n=read();
  27. for (int i=;i<=n;i++)
  28. left[i]=read(),right[i]=read();
  29. memset(f[],~0x3f,sizeof(f[]));
  30. f[][E]=;
  31. for (int i=;i<=n;i++)
  32. for (int j=-INF;j<=INF;j++) {
  33. f[i][j+E]=f[i-][j+E];
  34. if (j-left[i]<-INF||j-left[i]>INF) continue;
  35. f[i][j+E]=max(f[i-][j-left[i]+E]+right[i],f[i][j+E]);
  36. }
  37. for (int j=;j<=INF;j++) if (f[n][j+E]>=) ans=max(ans,f[n][j+E]+j);
  38. cout<<ans<<'\n';
  39. return ;
  40. }

smrtfun.cpp

HGOI 20190218 题解的更多相关文章

  1. HGOI 20181028 题解

    HGOI 20181028(复赛备考) /* 真是暴力的一天,最后一题MLE?由于数组开得太大了!!! 270滚粗 考场上好像智商高了很多?!(假的) */ sol:暴力求解,然后没有数据范围吐槽一下 ...

  2. HGOI 20190310 题解

    /* 又是又双叒叕WA的一天... 我太弱鸡了... 今天上午打了4道CF */ Problem 1 meaning 给出q组询问,求下列函数的值$ f(a) = \max\limits_{0 < ...

  3. HGOI 20190303 题解

    /* 记一串数字真难. 5435 今天比赛又是hjcAK的一天. 今天开题顺序是312,在搞T1之前搞了T3 昨天某谷月赛真是毒瘤. 但是讲评的同学不错,起码T4看懂了... 构造最优状态然后DP的思 ...

  4. HGOI 20180224 题解

    /* The Most Important Things: ljc chat with fyh on QQTa说期末考Ta数学74分感觉不好但是我觉得fyh是地表最强的鸭~~(of course en ...

  5. HGOI 20190217 题解

    /* for me,开训第一天 /beacuse 文化课太差被抓去补文化课了... 看一眼题 : AK局? 但是,Wa on test #10 in problem C 290! (就差那么一咪咪) ...

  6. HGOI 20181103 题解

    problem:把一个可重集分成两个互异的不为空集合,两个集合里面的数相乘的gcd为1(将集合中所有元素的质因数没有交集) solution:显然本题并不是那么容易啊!考场上想了好久.. 其实转化为上 ...

  7. HGOI 20181101题解

    /* 又是爆0的一天(不知道今年高考难不难,反正今天(信息学)真的难!) */ solution:对于两个数相加,有一个显然的结论就是要么不进位(相对于位数大的),要么(进最多一位) 然后对于整个数组 ...

  8. HGOI 20191108 题解

    Problem A 新婚快乐 一条路,被$n$个红绿灯划分成$n+1$段,从前到后一次给出每一段的长度$l_i$,每走$1$的长度需要$1$分钟. 一开始所有红绿灯都是绿色的,$g$分钟后所有红绿灯变 ...

  9. HGOI 20191107 题解

    Problem A 树状数组 给出下列$C++$代码: 设区间加操作$modify(l,r)$为调用两次$update(r,1)$和$update(l-1,-1)$ 设$f(l,r)$表示在初始$cn ...

随机推荐

  1. DELL升级bios方式

    升级过程其实很简单 1.官网下载exe文件,放入U盘 2.重启电脑F12选择升级bios 3.选择U盘里面的升级文件 4.重点来了!!! boot options 是什么? 就是boot设置里面自己自 ...

  2. ABP从入门到精通(4):使用基于JWT标准的Token访问WebApi

    项目:asp.net zero 4.2.0 .net core(1.1) 版本 我们做项目的时候可能会遇到需要提供api给app调用,ABP动态生成的WebApi提供了方便的基于JWT标准的Token ...

  3. WEB 小案例 -- 网上书城(四)

    针对于这个小案例我们今天讲解结账操作,也是有关这个案例的最后一次博文,说实话这个案例的博文写的很糟糕,不知道该如何去表述自己的思路,所以内容有点水,其实说到底还是功力不够. 处理思路 点击结账,发送结 ...

  4. Mac下通过VMware Fusion安装centos虚拟机操作记录

    下面介绍下利用VMware Fusion工具在Mac上安装centos虚拟机的做法:1)下载VMware Fusion工具下载地址(包括注册码):http://www.macx.cn/thread-2 ...

  5. Supervisor (进程管理利器) 使用说明 - 运维笔记

    一.Supervisor简单介绍supervisor是一个 Client/Server模式的系统,允许用户在类unix操作系统上监视和控制多个进程,或者可以说是多个程序.supervisor与laun ...

  6. 个人博客作业Week 3 ——微软必应词典客户端

    产品:必应词典客户端 (http://bing.msn.cn/dict/)必应词典有PC,Win8/10, Windows Phone,iPhone,Android,iPad 客户端 选择客户端为:i ...

  7. Android Studio下创建menu布局文件

    一.问题: android studio项目中没有看到menu文件夹: 在android studio项目中想要添加menu布局文件,一开始我的做法是:直接在res文件夹右键选择xml文件来添加,如下 ...

  8. elastic-search-kibana-in-docker-dotnet-core-app

    [翻译] 使用ElasticSearch,Kibana,ASP.NET Core和Docker可视化数据   原文地址:http://www.dotnetcurry.com/aspnet/1354/e ...

  9. 为什么要用Thrift

    Why Thrift, Why not HTTP RPC(JSON+gzip) https://stackoverflow.com/questions/9732381/why-thrift-why-n ...

  10. ping命令返回的TTL值判断操作系统

    通过简单的ping命令,查看返回的TTL值来判断对方的操作系统 生存时间(TTL)是IP分组中的一个值,网络中的路由器通过察看这个值就可以判断这个IP分组是不是已经在网络中停留了很久,进而决定是否要将 ...