昨天晚上熬夜熬得有点严重,今天比赛的时候状态不好,成绩爆炸。。。

 不得不说BLUESKY007 出的题还是相当不错的,也为我提醒了几个需要补的漏洞方向,这里作一下整理。

\(Task 1\):探索

\(1.1\) 题目描述

 古希腊哲学家柏拉图曾经在他的著作中这样描述道:“有这样一群囚徒,他们终生居住在一个黑暗的洞穴中,脖子和脚被锁住,无法环顾四周,只能面向洞穴岩壁。在囚徒身后,”有一堆篝火。在篝火与囚徒之间,有着形形色色的物体,火光将那些物体的影子投射到囚徒面前的岩壁上。这些二维影子就是囚徒们所能看到的全部,他们认为这就是现实世界。但真实情况是,世界要比他们他们所认为的二维世界多一个维度,锁链让他们无法回头看到这个真实的世界。然而这个真实的世界却远远比岩壁上的一切丰富多彩。”那么是不是也有可能我们现在生活的世界也是四维空间的一个投影?是不是宇宙大爆炸之前的纪元里,那时的空间要比我们现在的宇宙空间多出一个维度,而我们的宇宙诞生于高维宇宙中的一次恒星坍塌——这次坍塌在四维宇宙中产生了一个四维黑洞,而黑洞的三维表面,就是我们生活的宇宙?——

 沉浸在对高维时空幻想中的\(BLUESKY007\)想着想着,一不小心就睡着了。在梦里,她竟然来到了四维的神奇世界!这个世界被\(n\)堵三维的墙划分成了很多不同的区域。\(BLUESKY007\)感到很兴奋,于是她想要探索这个神奇的世界,但是每次她只能探索同一个区域。探索一个区域就可以获得一点开心值。

 由于这个四维世界的不确定性,她的开心指数也不会一样,现在她想要知道自己的开心值最大能达到多少。(由于答案一定会很大,所以只需要输出对\(m\)取模后的结果)

\(1.2\) 输入输出格式:

 输入:一行两个整数\(n,m\)

 输出:一行一个整数\(ans\),表示开心指数

\(discover.in\) \(discover.out\)
\(5,5\) \(1\)

\(1.3\) 样例输入输出解释

\(k[1]=2,k[2]=4,k[3]=8,k[4]=16,k[5]=31\)

\(1.4\) 数据范围与约定

  • 对于\(30\%\)的数据,\(n\le10^6,m\le10^5\)

  • 对于\(75\%\)的数据,\(n \le 10^{12},m \le 10^9\)

  • 对于\(100\%\)的数据,\(n,m \le 10^{18}\)

 看到高维的题目,第一想法当然是从低维找规律。但是由于本蒻昨晚修仙,今天早上脑子不清楚,所以直到最后才找到规律,只好匆忙打了一个30分暴力上去。

 先说基础想法,考虑下面一些情况:

拆分空间\维度 一维-零维 二维-一维 三维-二维 四维-三维
\(0\) 1 1 1 1
\(1\) 2 2 2 2
\(2\) 3 4 4 4
\(3\) 4 7 8 8
\(4\) 5 11 15 16

 简单来说就是线被点分,面被线分,体被面分的数量。通过列表会清晰的发现其差分规律,直接大力构造矩阵进行加速线性递推就可以了。

 值得注意的问题是快速乘的用法。实际上快速乘还有一种O(1)的写法,但是因为害怕出锅,所以这里不讨论,反正我也不是高端选手嘛。

 思想上类似快速幂,复杂度O(logn)。相当于把两数相乘,拆成一个数乘另一个数的二进制累加,常用于long long乘法取模爆精度的情况。

  1. inline lint mul(lint x,lint y){
  2. //mod m
  3. lint res=0;
  4. while(y){
  5. if(y&1)res=(res+x)%m;
  6. y>>=1;
  7. x=(x+x)%m;
  8. }
  9. return res;
  10. }

 代码如下:

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<iostream>
  4. #define lint long long
  5. using namespace std;
  6. struct Matrix{
  7. lint mp[6][6];
  8. void Init(){
  9. memset(mp,0,sizeof(mp));
  10. }
  11. void Unit(){
  12. memset(mp,0,sizeof(mp));
  13. for(int i=0;i<5;++i){
  14. mp[i][i]=1;
  15. }//初始化为单位矩阵
  16. }
  17. };
  18. lint tmp[5][5]={
  19. {1,1,0,0,0},
  20. {0,1,1,0,0},
  21. {0,0,1,1,0},
  22. {0,0,0,1,0},
  23. {1,0,0,0,1}
  24. };//构造转移矩阵
  25. lint n,m,ans[1][5],bg[1][5]={1,1,1,1,1};
  26. //构造初始矩阵
  27. inline lint mul(lint x,lint y){
  28. //mod m
  29. lint res=0;
  30. while(y){
  31. if(y&1)res=(res+x)%m;
  32. y>>=1;
  33. x=(x+x)%m;
  34. }
  35. return res;
  36. }
  37. Matrix __mul(Matrix mat_1,Matrix mat_2){
  38. Matrix res;
  39. res.Init();
  40. for(int i=0;i<5;++i){
  41. for(int j=0;j<5;++j){
  42. for(int k=0;k<5;++k){
  43. res.mp[i][k]=(res.mp[i][k]+mul(mat_1.mp[i][j],mat_2.mp[j][k]))%m;
  44. }
  45. }
  46. }
  47. return res;
  48. }
  49. Matrix __pow(Matrix mat,lint p){
  50. Matrix res;
  51. res.Unit();
  52. while(p){
  53. if(p&1){
  54. p^=1;
  55. res=__mul(res,mat);
  56. }
  57. p>>=1;
  58. mat=__mul(mat,mat);
  59. }
  60. return res;
  61. }
  62. int main(){
  63. // freopen("discover.in","r",stdin);
  64. // freopen("discover.out","w",stdout);
  65. cin>>n>>m;
  66. Matrix mat,res;
  67. for(int i=0;i<5;++i){
  68. for(int j=0;j<5;++j){
  69. mat.mp[i][j]=tmp[i][j];
  70. }
  71. }
  72. res=__pow(mat,n);//mat^n
  73. for(int i=0;i<1;++i){
  74. for(int j=0;j<5;++j){
  75. for(int k=0;k<5;++k){
  76. ans[i][k]=(ans[i][k]+bg[i][j]*res.mp[j][k])%m;
  77. }
  78. }
  79. }
  80. cout<<ans[0][3]<<endl;
  81. }

 为了保证写法的通用性与鲁棒性,这里我选择构造出来初始矩阵和答案矩阵,这个题不构造也是可以的。


\(Task 2\): 水果蛋糕

\(2.1\) 题目描述

 BLUESKY007要过生日了,为此朋友们准备给她买一个\(nm\)的水果蛋糕,但是在订蛋糕的时候却出现了问题:

 蛋糕是方形的,因为水果颗粒放整齐才好看,所以水果颗粒必须按行按列地摆放(也就是如果建立平面直角坐标系,它们的坐标必须都是整数).

 她的朋友们想要蛋糕店多放点水果,但是由于摆放得太密集也不好看,所以蛋糕店拒绝在和任意的水果颗粒相距 \(\sqrt{13}\)的地方摆放水果颗粒.(距离按照坐标计算)

 她的朋友们想知道蛋糕上最多能摆放多少水果颗粒,但是由于她们没有\(BLUESKY007\)聪(\(rui\))慧(\(zhi\)),所以她们找到了你来帮忙.

\(2.2\) 输入输出格式

 输入:一行两个整数\(n,m\)

 输出:一行一个整数表示答案

\(cake.in\) \(cake.out\)
1 4 4
\(cake.in\) \(cake.out\)
3 4 10

\(2.3\) 样例解释

 如图所示,左图为样例1的实现方案,右图为样例2的实现方案之一

\(2.4\) 数据范围与约定

  • 对于\(20\%\)的数据,\(n,m\le5\)

  • 对于另\(30\%\)的数据,\(n=3,m\le10^4\)

  • 对于另\(30\%\)的数据,\(n=4,m\le10^9\)

  • 对于\(100\%\)的数据,\(n,m\le10^9\)

 这个题目的想法让我很意外,以前很少见到类似这样较多特判的构造。

 首先题目很明确的告诉你了,这个题不能搜索。尽管如此,暴搜打表找规律还是可以的,不过似乎并不需要。

  • 首先考虑对\(n,m\le5\)的情况,可以直接用纸推出来。
  • 其次对于\(n=3\)的情况,可以构造出来一种最优情况,是中间全满,上下6个一循环。
  • 对于\(n=4\)同理,也可以得到循环的最优构造。
  • 对于更大的情况,因为上下也会互相干涉了,所以每两个格子里面最多放一个。考虑区分行列奇偶情况,特判求解即可。

 让人意外的一点是:这个题目的正解就是多个特判,而且部分分之间关联并不大,和往常那种层层递进引向正解的不太相似。虽然正解也好写,但是即使构造出来正确答案也很难不怀疑自己程序的正确性。所以果然,本蒻还是要多练习多见见世面啊QWQ

 为了方便本蒻这里做了一下关于\(n,m\)大小的处理,详见代码。

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<iostream>
  4. #include<algorithm>
  5. #define lint long long
  6. using namespace std;
  7. lint n,m;
  8. lint r_3[6]={0,3,6,9,10,11};
  9. lint r_4[6]={0,4,8,10,12,12};
  10. int main(){
  11. // freopen("cake.in","r",stdin);
  12. // freopen("cake.out","w",stdout);
  13. cin>>n>>m;
  14. if(n>m)swap(n,m);
  15. if(n<=2){
  16. cout<<n*m<<endl;
  17. return 0;
  18. }
  19. if(n==3){
  20. cout<<(m/6)*12+r_3[m%6]<<endl;
  21. return 0;
  22. }
  23. if(n==4){
  24. cout<<(m/6)*12+r_4[m%6]<<endl;
  25. return 0;
  26. }
  27. if(n>=5){
  28. if(m&1)swap(n,m);//m为奇数就交换
  29. if(~m&1&&~n&1){
  30. cout<<n*m/2<<endl;
  31. } //两个偶数
  32. else if(n&1&&~m&1){
  33. //n为奇,m为偶
  34. cout<<(n-1)*m/2+(n+1)/2;
  35. }else{
  36. cout<<((n-1)*(m-1)/2)+(n+m)/2<<endl;
  37. }
  38. return 0;
  39. }
  40. }

\(Task 3\):好朋友

\(3.1\) 题目描述

 \(BLUESKY007\)有很多关系很好的朋友,他们无一例外,名字均由数字组成(首字符不为\(0\))且含有"\(007\)"(例如"\(10007\)","\(10707\)"就是她的好朋友,而"\(97037\)","\(70709\)"不是),即对于字符串\(S\)存在\(i,j,k(i<j<k)\)满足\(\bar{Si}\bar{Sj}\bar{Sk}=“007”\)

 虽然\(BLUESKY007\)眼力极佳,一眼就能看出一个人是不是自己的好朋友,但\(BLUESKY007\)是个蒟蒻,她并不擅长数数,但她又想知道在\([li,ri]\)内有多少人是自己的好朋友,所以就找到了你来帮忙.

 她会向你询问\(T\)次,由于询问次数可能很多,所以你只需要告诉她\(T\)次询问答案的异或和即可.

\(3.2\) 输入输出格式:

 输入:第一行一个整数\(T\),表示询问个数. 接下来\(T\)行,每行两个整数\([li,ri]\)

 输出:一行一个整数表示答案.

\(friend.in\) \(friend.out\)
3 0
1 1000
233 666
999 999

\(3.3\) 样例解释

 在\(0~1000\)范围内不存在与题目要求相符的含有\(“007”\)的数,所以三次询问的答案都是\(0\).

3.8数据范围与约定

  • 对于20%的数据,\(li \le ri \le 10^3\)

  • 对于60%的数据,\(t \le 50,li \le ri \le 5*10^5\)

  • 对于100%的数据,\(t \le 10^5,li \le ri \le 10^{18}\)

 这个题目啊,\(exciting\)。\(dreagonm\)说这个题是个送温暖的题目,然而本蒻不会数位DP所以凉凉,60分暴力走人。(幸好我晕乎着还能写出来暴力)学会之后发现数位DP除了处理起来复杂一点,其他和普通DP区别好像不是很大,之后几天,除了练\(NOIp\)题目顺手再多练练数位\(DP\)吧QWQ

 现在我们来考虑一下情况:

  • 对于目前还没有选到的情况,只需要当前这个数选0且没有前导0,就可以转移到选一个有效0的情况
  • 对于当前选择一个有效0的情况,只需要当前这个数选0,就可以转移到选择两个有效0的情况
  • 对于当前选择两个有效0的情况,只需要当前这个数选7,就可以转移到最终的目标情况
  • 对于已经成型的情况只需要保证上下不越界,就可以往后慢慢累加
  • 到达边界就返回值0/1(是否有合法情况),由调用处累计求答案
  • 如果本位置上对于数字大小没有限制就储存(有限制的话答案会不通用),同理不限制的时候进行记忆化调用。

 大概就这样,好像不是很难,明天继续刷类似的题目去。

 代码里注释很清晰。

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<iostream>
  4. #define lint long long
  5. using namespace std;
  6. lint t,l,s,ch,r,ans,arr[20],res[20][4];
  7. inline lint read(){
  8. s=0,ch=getchar();
  9. while(ch==' '||ch=='\n')ch=getchar();
  10. while('0'<=ch && ch<='9')
  11. s=s*10+ch-'0',
  12. ch=getchar();
  13. return s;
  14. }
  15. lint dfs(lint pos,lint cmd,lint led,lint lim){
  16. //pos->当前位置
  17. //cmd->控制状态
  18. //led->前导0<true/false>
  19. //lim->是否受限<true/false>
  20. if(pos==0)//{
  21. // if(cmd==3){
  22. // //当前状态->已经达成
  23. // return 1;
  24. // }else{
  25. // //未达成->不累加
  26. // return 0;
  27. // }
  28. return cmd==3;
  29. //}
  30. if(!led && !lim && res[pos][cmd])//{
  31. return res[pos][cmd];
  32. //}
  33. lint maxn=lim?arr[pos]:9,tmp=0;
  34. //可以取的数字上限->根据前面的数是否完全相等确定
  35. for(lint i=0;i<=maxn;++i){
  36. //i表示当前取的数
  37. if(cmd==0)//{
  38. //当前还什么都没有
  39. //如果选的数字是0而且没有前导即可
  40. //前导的状态:原来有的->如果还是0就继续有
  41. //限制的状态:原来限制的->如果等于上限就继续有
  42. tmp+=dfs(pos-1,!i&!led,led&!i,lim&(i==arr[pos]));
  43. else if(cmd==1)
  44. //已经有一个有效0,一定没有前导
  45. tmp+=dfs(pos-1,(i==0)+1,0,lim&(i==arr[pos]));
  46. else if(cmd==2)
  47. //有两个有效0,需要一个7,没有前导
  48. tmp+=dfs(pos-1,(i==7)+2,0,lim&(i==arr[pos]));
  49. else if(cmd==3)
  50. tmp+=dfs(pos-1,3,0,lim&(i==arr[pos]));
  51. }
  52. if(!led && !lim)res[pos][cmd]=tmp;
  53. return tmp;
  54. }
  55. inline lint sol(lint x){
  56. //get ans in [1,x];
  57. memset(arr,0,sizeof(arr));
  58. memset(res,0,sizeof(res));
  59. lint cnt=0;
  60. while(x!=0)//{
  61. arr[++cnt]=x%10,
  62. x/=10;//转化进数组记录每一位
  63. // }
  64. // for(int i=1;i<=cnt;++i){
  65. // for(int j=0;j<=3;++j){
  66. // printf("%lld ",res[i][j]);
  67. // }
  68. // puts("");
  69. // }
  70. return dfs(cnt,0,1,1);
  71. //从高位向低位找
  72. }
  73. int main(){
  74. // scanf("%lld",&t);
  75. t=read();
  76. while(t--){
  77. // scanf("%lld%lld",&l,&r);
  78. l=read(),r=read();
  79. ans^=(sol(r)-sol(l-1));
  80. //这里一次sol解决的是所有数位的问题,需要减去
  81. // printf("%lld\n",(sol(r)-sol(l-1)));
  82. }
  83. printf("%lld\n",ans);
  84. }

@BLUESKY007

【BLUESKY的NOIp模拟赛】解题报告的更多相关文章

  1. 2018.10.16 NOIP模拟赛解题报告

    心路历程 预计得分:\(100 + 100 + 20 = 220\) 实际得分:\(100 + 100 + 30 = 230\) 辣鸡模拟赛.. T1T2都是一眼题,T3考验卡常数还只有一档暴力分. ...

  2. 20161022 NOIP模拟赛 解题报告

     好元素 [问题描述] 小A一直认为,如果在一个由N个整数组成的数列{An}中,存在以下情况: Am+An+Ap = Ai (1 <= m, n, p < i <= N ,  m,n ...

  3. 9月24日noip模拟赛解题报告

    1.校门外的树(tree.c/cpp/pas 128M,1s) Description LSGJ扩建了,于是校门外有了一条长为L的路.路上种了一排的树,每相邻两棵树之间的距离为1,我们可以把马路看成一 ...

  4. 2018-11-1 NOIP 模拟赛解题报告

    T1 Domino 多米诺骨牌 题目大意 给你N个骨牌,上下各有一个数,要使上面一排的和为偶数,同时下面一排的和也为偶数,最多要翻转多少次?如果无法达成那么输出-1. 解法 水题秒切 根据数的奇偶性质 ...

  5. 2015-9-13 NOIP模拟赛解题报告(by hzwer)

    小奇挖矿 「题目背景」 小奇要开采一些矿物,它驾驶着一台带有钻头(初始能力值w)的飞船,按既定路线依次飞过喵星系的n个星球. 「问题描述」 星球分为2类:资源型和维修型. 1.资源型:含矿物质量a[i ...

  6. 2018.10.03 NOIP+ 模拟赛 解题报告

    得分: \(30+5+0=35\)(考得真不咋滴) \(T1\):奥义商店(点此看题面) 以为很简单,对着这题想了一个多小时,最后果断打了个暴力交了... ... 看完题解发现其实也不是很难. 对于\ ...

  7. 2017.9.17校内noip模拟赛解题报告

    预计分数:100+60+60=220 实际分数:100+60+40=200 除了暴力什么都不会的我..... T1 2017.9.17巧克力棒(chocolate) 巧克力棒(chocolate)Ti ...

  8. 10.30 NFLS-NOIP模拟赛 解题报告

    总结:今天去了NOIP模拟赛,其实是几道USACO的经典的题目,第一题和最后一题都有思路,第二题是我一开始写了个spfa,写了一半中途发现应该是矩阵乘法,然后没做完,然后就没有然后了!第二题的暴力都没 ...

  9. 2018.10.26NOIP模拟赛解题报告

    心路历程 预计得分:\(100 + 100 + 70\) 实际得分:\(40 + 100 + 70\) 妈妈我又挂分了qwq..T1过了大样例就没管,直到临考试结束前\(10min\)才发现大样例是假 ...

  10. 2018.10.17NOIP模拟赛解题报告

    心路历程 预计得分:\(100 + 100 +100\) 实际得分:\(100 + 100 + 60\) 辣鸡模拟赛.. 5min切掉T1,看了一下T2 T3,感觉T3会被艹爆因为太原了.. 淦了20 ...

随机推荐

  1. [LeetCode] 307. Range Sum Query - Mutable 解题思路

    Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclusive ...

  2. Hybrid APP基础篇(一)->什么是Hybrid App

    最新更新 一个开源的快速混合开发框架:https://github.com/quickhybrid/quickhybrid Android.iOS.JS三端内容初步都已经完成,有完善的设计思路.教程以 ...

  3. Buy the Ticket HDU 1133

    传送门 [http://acm.hdu.edu.cn/showproblem.php?pid=1133] 题目描述和分析 代码 #include<iostream> #include< ...

  4. 2-Twenty Fourth Scrum Meeting-20151230

    前言 因为服务器关闭,我们的开发项目也遭遇停滞一个星期.与网站开发负责人员协商之后,29号开放服务器.我们的项目也能够继续下去.比规定的开发时间(截止为2015/12/29)推迟. 事项安排 1.开发 ...

  5. linux第四次读书笔记

    第四章:进程调度 一.多任务 1.非抢占式多任务 进程会一直执行直到自己主动停止运行(这一步骤称为让步) 2.抢占式多任务 Linux/Unix使用的是抢占式的方式:强制的挂起进程的动作就叫做抢占.进 ...

  6. 《Linux内核设计与实现》读书笔记 3

    第三章 进程管理 3.1进程 概念: 进程:处于执行期的程序.但不仅局限于程序,还包含其他资源(打开的文件,挂起的信号,内核内部数据,处理器状态,一个或多个具有内催音社的内存地址空间及一个或多个执行线 ...

  7. 13.14.15.16.17&《一个程序猿的生命周期》读后感

    13.TDS 的标准是什么,怎么样才能认为他是一个标准的TDS?? 14.软件的质量包括哪些方面,如何权衡软件的质量? 15.如何解决功能与时间的矛盾,优秀的软件团队会发布有已知缺陷的软件么? 16. ...

  8. Java的常用命令javac与java

    javac 可以使用javac -h来查看常用的命令: -> ~ # javac -help 用法: javac <options> <source files> 其中, ...

  9. Angular $location获取端口号

    <!DOCTYPE html><html ng-app="myApp"><head lang="en"> <meta ...

  10. ARIMA模型识别、计算p、q值

    #-*- coding: utf-8 -*- #确定最佳p.d.q值 import pandas as pd #参数初始化 discfile = '../data/discdata_processed ...