题目质量还是比较高的,只是当时澳大利亚方面出了一点问题?最后造成了区分度非常迷的局面。

纵观三道题,T1是披着交互外衣的提答题,T2是披着交互外衣的传统题,T3是一道据说近年来APIO最水的一道传统题,然而对于不敢相信T3水的选手来说只能靠硬搞两道交互拿分了。

T1 Rainbow

没脸写题解和程序了。

Subtask 1直接floodfill一下,Subtask 2听说前缀和讨论一下,后面听说数据结构维护一下。

T2 Koala

这个感觉可以写一篇交互库玩耍记了,感觉前几个部分分就是在考调戏交互库的水平。

首先看Subtask 1只有4分,而且场上超过300人拿了这4分,但是我不会怎么办?

猜一个结论,随便选一个旁边放一个宝石,其它都不放,然后koala没放宝石的那个就是最小的那个。就过了。(我竟然没想到)

然后如果光搞Subtask 2感觉想得出结论会比较吃力,因为这题实际上是一道构造题。这个时候就需要在交互库上做文章了。

看一会代码发现交互库实际上就是一个无脑DP(于是就可以确定交互库占用的时空复杂度了),并没有什么可以利用的地方。但是我们可以把它改成一个能够做实验的程序,可供我们猜结论使用,如下

  1. #include<cstdio>
  2. #include<ctime>
  3. #include<algorithm>
  4. #define rep(i,l,r) for (int i=(l); i<=(r); i++)
  5. using namespace std;
  6.  
  7. int N,W,P[],b[],r[],c[];
  8.  
  9. void playRound(int *B, int *R) {
  10. int i, j;
  11.  
  12. int cache[][];
  13. int num[][];
  14. char taken[][];
  15.  
  16. for (i=;i<;++i) {
  17. cache[][i] = ;
  18. num[][i] = ;
  19. }
  20.  
  21. for (i=;i<N;++i) {
  22. int v = B[i]+;
  23. int ii = i&;
  24. int o = ii^;
  25. for (j=;j<=W;++j) {
  26. cache[ii][j] = cache[o][j];
  27. num[ii][j] = num[o][j];
  28. taken[i][j] = ;
  29. }
  30. for (j=W;j>=v;--j) {
  31. int h = cache[o][j-v] + P[i];
  32. int hn = num[o][j-v] + ;
  33. if (h > cache[ii][j] || (h == cache[ii][j] && hn > num[ii][j])) {
  34. cache[ii][j] = h;
  35. num[ii][j] = hn;
  36. taken[i][j] = ;
  37. } else {
  38. taken[i][j] = ;
  39. }
  40. }
  41. }
  42.  
  43. int cur = W;
  44. for (i=N-;i>=;--i) {
  45. R[i] = taken[i][cur] ? (B[i] + ) : ;
  46. cur -= R[i];
  47. }
  48. }
  49.  
  50. int main(){
  51. srand(time(NULL));
  52. N=; W=;
  53. for (int i=; i<N; i++){
  54. int k=rand()%N+; while (c[k]) k=rand()%N+;
  55. c[k]=; P[i]=k;
  56. }
  57.  
  58. b[]=b[]=;
  59. for (int i=; i<; i++) b[i]=;
  60.  
  61. playRound(b,r);
  62. for (int i=; i<N; i++){
  63. printf("%3d%3d ",i,r[i]);
  64. if ((i+)%==) puts("");
  65. }
  66. return ;
  67. }

对于如何分配b数组,只需要改主函数里的两句话即可。

通过实验发现,现在已经确定的区间为[1,100],如果每个位置放一个的话,就可以确定[51,100],然后这部分放2个其余都不放的话可以确定[76,100],这部分再放4个其余不放的话可以确定[92,100],这部分放11个可以确定[100,100]。

这样我们真好用了4次确定了100的位置。

考虑如何测试,写一个数据生成程序:

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<cstring>
  4. #include<sys/timeb.h>
  5. #include<cstdlib>
  6. #include<fstream>
  7. #define rep(i,l,r) for (int i=(l); i<=(r); i++)
  8. typedef long long ll;
  9. using namespace std;
  10.  
  11. ofstream fout,fres;
  12.  
  13. const int N=;
  14. int b[N];
  15.  
  16. void insd(){
  17. struct timeb tp; ftime(&tp);
  18. srand(tp.time*+tp.millitm);
  19. }
  20.  
  21. int sj(int l,int r){ return rand()%(r-l+)+l; }
  22.  
  23. int main(){
  24. insd();
  25. fout.open("koala.in"); fres.open("result");
  26. ios::sync_with_stdio(false);
  27.  
  28. int F=sj(,),G=sj(,);
  29. fout<<F<<' '<<G<<endl;
  30. if (F==){
  31. while (G--){
  32. fout<<"100 100 ";
  33. rep(i,,) b[i]=;
  34. rep(i,,){
  35. int k=sj(,); while (b[k]) k=sj(,);
  36. fout<<k<<' '; b[k]=;
  37. if (k==) fres<<i<<endl;
  38. }
  39. fout<<endl;
  40. }
  41. }else if (F==){
  42. while (G--){
  43. fout<<"100 100 ";
  44. rep(i,,) b[i]=;
  45. rep(i,,){
  46. int k=sj(,); while (b[k]) k=sj(,);
  47. fout<<k<<' '; b[k]=;
  48. if (k==) fres<<i<<endl;
  49. }
  50. fout<<endl;
  51. }
  52. }else if (F==){
  53. while (G--){
  54. int x=,y=;
  55. fout<<"100 100 ";
  56. rep(i,,) b[i]=;
  57. rep(i,,){
  58. int k=sj(,); while (b[k]) k=sj(,);
  59. fout<<k<<' '; b[k]=;
  60. if (!x) x=k; else if (!y) fres<<((k>x)?:)<<endl,y=k;
  61. }
  62. fout<<endl;
  63. }
  64. }
  65. fout.close(); fres.close();
  66. return ;
  67. }

这份代码在生成数据的同时将答案输出到了result文件里,方便对拍。对拍的代码:

  1. g++ make.cpp -o make -g -Wall
  2. g++ koala.cpp grader.cpp -o koala -static -std=c++
  3. while true; do
  4. echo ---------------------
  5. ./make
  6. time ./koala<koala.in>koala.out
  7. if !(diff -w koala.out result); then exit; fi
  8. done

现在看Subtask 3,用上面的程序实验发现,其余都不放,如果b[0]和b[1]都放15的话,两个都不会被选。这样我们在[1,15]内二分,每次保证b[0]=b[1],直到发现有一个选了而另一个没选就可以返回答案了。

这是C<=4的算法,能拿14分,满分是将区间人工细化以减小一次机器搜索。

前33分程序:

  1. #include "koala.h"
  2. #include<cstdio>
  3. using namespace std;
  4.  
  5. const int N=;
  6. int b[N],r[N],c[N];
  7.  
  8. int minValue(int N, int W) {
  9. for (int i=; i<N; i++) b[i]=; b[]=;
  10. playRound(b,r);
  11. for (int i=; i<N; i++) if (!r[i]) return i;
  12. return ;
  13. }
  14.  
  15. int maxValue(int N, int W) {
  16. for (int i=; i<N; i++) b[i]=,c[i]=;
  17. playRound(b,r);
  18. for (int i=; i<N; i++) if (!r[i]) c[i]=;
  19. for (int i=; i<N; i++) if (!c[i]) b[i]=; else b[i]=;
  20. playRound(b,r);
  21. for (int i=; i<N; i++) if (r[i]!=) c[i]=;
  22. for (int i=; i<N; i++) if (!c[i]) b[i]=; else b[i]=;
  23. playRound(b,r);
  24. for (int i=; i<N; i++) if (r[i]!=) c[i]=;
  25. for (int i=; i<N; i++) if (!c[i]) b[i]=; else b[i]=;
  26. playRound(b,r);
  27. for (int i=; i<N; i++) if (r[i]==) return i;
  28. return ;
  29. }
  30.  
  31. int greaterValue(int N, int W) {
  32. int L=,R=;
  33. while (L<R){
  34. int mid=(L+R)>>;
  35. b[]=b[]=mid;
  36. for (int i=; i<N; i++) b[i]=;
  37.  
  38. playRound(b,r);
  39.  
  40. if (!r[] && r[]) return ;
  41. if (!r[] && r[]) return ;
  42.  
  43. if (!r[] && !r[]) R=mid-; else L=mid+;
  44. }
  45. return L;
  46. }
  47.  
  48. void allValues(int N, int W, int *P) { if (W == *N) { } else { } }

Subtask 4是给数组排序,发现如果b[x]和b[y]各放100个的话,肯定有一个被选而另一个不选,也就是说可以用一次游戏完成两个数的比较。

所以我们手工实现一个$O(n\log n)$的比较排序算法即可。

或许可以直接写进std::sort的cmp里,没试过。

Subtask 5没做。

T3 merchant

首先第一眼分数规划,第二眼spfa判负环,问题解决了一半。

然后发现因为每次买卖涉及两个城市,所以一般做法没办法给每条边赋值。

考虑根据决策重建图,如果两个点u和v又一次买卖,一定是u的买入价和v的卖出价中差值最大的那个,所以根据这个连边,构成一个边数$n^2$的图,就可以直接跑spfa了。

比较坑的情况是一个城市同一个商品的卖出价可能大于买入价,也就是说留在这里不走可以一直赚钱。但题目显然是不允许这样的。

  1. #include<cstdio>
  2. #include<algorithm>
  3. #define rep(i,l,r) for (int i=l; i<=r; i++)
  4. typedef long long ll;
  5. using namespace std;
  6.  
  7. const int N=,M=,inf=;
  8. int n,m,K,u,v,w,mx,flag,mid,vis[N],val[N][N],mp[N][N],a[N][M],b[N][M];
  9. ll d[N];
  10.  
  11. void spfa(int x){
  12. if (flag) return; vis[x]=;
  13. rep(i,,n) if (i!=x && mp[x][i]<inf && d[i]>d[x]+1ll*mp[x][i]*mid-val[x][i]){
  14. d[i]=d[x]+1ll*mp[x][i]*mid-val[x][i];
  15. if (vis[i]) { flag=; return; } else spfa(i);
  16. }
  17. vis[x]=;
  18. }
  19.  
  20. int jud(int mid){
  21. rep(i,,n) vis[i]=d[i]=; flag=;
  22. rep(i,,n){ spfa(i); if (flag) return ; }
  23. return ;
  24. }
  25.  
  26. int main(){
  27. freopen("merchant.in","r",stdin);
  28. freopen("merchant.out","w",stdout);
  29. scanf("%d%d%d",&n,&m,&K);
  30. rep(i,,n) rep(j,,K) scanf("%d%d",&a[i][j],&b[i][j]),mx=max(mx,b[i][j]);
  31. rep(i,,n) { rep(j,,n) mp[i][j]=inf; mp[i][i]=; }
  32. rep(i,,m) scanf("%d%d%d",&u,&v,&w),mp[u][v]=min(mp[u][v],w);
  33. rep(k,,n) rep(i,,n) rep(j,,n) mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]);
  34. rep(i,,n) rep(j,,n) rep(k,,K)
  35. if (i!=j && ~a[i][k] && ~b[j][k]) val[i][j]=max(val[i][j],b[j][k]-a[i][k]);
  36. int L=,R=mx,ans=;
  37. while (L<=R){
  38. mid=(L+R)>>;
  39. if (jud(mid)) ans=mid,L=mid+; else R=mid-;
  40. }
  41. printf("%d\n",ans);
  42. return ;
  43. }

APIO2017伪题解的更多相关文章

  1. 伪题解 洛谷 P1363 幻想迷宫(DFS)

    毒瘤题,做了一晚上抄题解A了 因为是抄题解,我也不好意思说什么了,就发篇博客纪念一下吧 #include<iostream> #include<cstring> #includ ...

  2. WC2018伪题解

    NOIP分数过低的场外选手,一个月之后才有幸膜到这套卷子.感觉题目质量很不错啊,可惜了T1乱搞可过,T2题目出锅非集训队员没有通知到,导致风评大幅被害. 感觉Cu的话随手写两个暴力就稳了,Ag的话T3 ...

  3. BZOJ4898 & BZOJ5367 & 洛谷3778:[APIO2017]商旅——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=4898 https://www.lydsy.com/JudgeOnline/problem.php? ...

  4. [CTSC2017]最长上升自序列(伪题解)(Dilworth's theorem+网络流)

    部分分做法很多,但每想出来一个也就多5-10分.正解还不会,下面是各种部分分做法: Subtask 1:k=1 LCS长度最长为1,也就是说不存在j>i和a[j]>a[i]同时成立.显然就 ...

  5. APIO2018练习赛伪题解

    传送门:https://pcms.university.innopolis.ru/statements/org/apio/2018/practice/statements.pdf 主要就在于后面三道构 ...

  6. 【伪题解】 [Offer收割]编程练习赛58

    [A:最大的K-偏差排列]: 第一次在hiho卡一题,所以暴力了搜索了一下,70分,后面回来打表找规律,规律是有和K有关的周期. 当K<=N/2时,成周期交叉变化,最后尾部部分单独考虑. 当K& ...

  7. 洛谷 P3952时间复杂度 (本地AC测评RE的伪题解)

    [题目描述] 小明正在学习一种新的编程语言 A++,刚学会循环语句的他激动地写了好多程序并 给出了他自己算出的时间复杂度,可他的编程老师实在不想一个一个检查小明的程序, 于是你的机会来啦!下面请你编写 ...

  8. PKUSC2018训练日程(4.18~5.30)

    (总计:共66题) 4.18~4.25:19题 4.26~5.2:17题 5.3~5.9: 6题 5.10~5.16: 6题 5.17~5.23: 9题 5.24~5.30: 9题 4.18 [BZO ...

  9. AHOI2018训练日程(3.10~4.12)

    (总计:共90题) 3.10~3.16:17题 3.17~3.23:6题 3.24~3.30:17题 3.31~4.6:21题 4.7~4.12:29题 ZJOI&&FJOI(6题) ...

随机推荐

  1. string 类型转换

    string转int "; int n = atoi(str.c_str()); cout << n << endl; int转string #include < ...

  2. linux bash善用判断式

    1.利用 test 指令的测试功能 $ test -e hello.sh && echo "ok" || echo "no" ok 2.首先,判 ...

  3. RTL2832U+R820T电视棒windows下安装sdr# 以及搭建ADS-B使用VirtualRadar看飞机的教程

    本文中提到的软件随后我会打包给出下载地址.这篇文章是我根据网上的教程和自己的经验修改的详细版本,为了方便入门新手.先来说说RTL2832U+R820T在windows下安装sdr#的方法.首先科普下s ...

  4. 谈一谈深度学习之semantic Segmentation

    上一次发博客已经是9月份的事了....这段时间公司的事实在是多,有写博客的时间都拿去看paper了..正好春节回来写点东西,也正好对这段时间做一个总结. 首先当然还是好好说点这段时间的主要工作:语义分 ...

  5. bzoj 2566 calc 拉格朗日插值

    calc Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 377  Solved: 226[Submit][Status][Discuss] Descr ...

  6. CF502C The Phone Number

    C. The Phone Number time limit per test 1 second memory limit per test 256 megabytes     Mrs. Smith ...

  7. 【洛谷 P1251】 餐巾计划问题 (费用流)

    题目链接 我做的网络流24题里的第一题.. 想是不可能想到的,只能看题解. 首先,我们拆点,将一天拆成晚上和早上,每天晚上会受到脏餐巾(来源:当天早上用完的餐巾,在这道题中可理解为从原点获得),每天早 ...

  8. 矩阵快速幂&T1

    T1 知识储备 在写这一题之前,我们首先要了解矩阵乘法(我就是因为不懂弄了好久...) 矩阵的运算()-----(信息学奥赛一本通之提高篇) 矩阵的加法减法是十分简单的,就是把2个矩阵上对应的位置相加 ...

  9. 10款最新CSS3/jQuery菜单导航插件

    这是我们在2014年收集的10款最新的CSS3 / jQuery菜单导航插件,不论从外观样式,还是功能扩展性,这些jQuery菜单一定可以满足大家的设计需求.这次我们收集的jQuery菜单,有水平 菜 ...

  10. 培训补坑(day8:树上倍增+树链剖分)

    补坑补坑.. 其实挺不理解孙爷为什么把这两个东西放在一起讲..当时我学这一块数据结构都学了一周左右吧(超虚的) 也许孙爷以为我们是省队集训班... 好吧,虽然如此,我还是会认真写博客(保证初学者不会出 ...