Begin
(题目的排序方式:难易程度)
什么是对拍:
对拍是一种在写完程序后,验证自己程序是不是正解的比较方便的方法.
实现过程:
对同一道题,再打一个暴力程序,然后用一些大数据等跑暴力程序来进行验证,通过和自己写的程序的输出进行比较来查错。
2019.08.04【NOIP普及组】模拟赛C组
(就一道入门难度,其他就是1道普及+提高,2道提高+省选-。那还是人吗?普及模拟考这么难???想给出题人寄刀片)
第三题 【2266. 古代人的难题】
2266. 古代人的难题
(File IO): input:puzzle.in output:puzzle.out时间限制: 1000 ms 空间限制: 60000 KB 具体限制题目描述
门打开了, 里面果然是个很大的厅堂。但可惜厅堂内除了中央的一张羊皮纸和一根精致的石笔,还有周围几具骷髅外什么也没有。 难道这就是王室的遗产? 小 FF 不信,他仔细阅读了羊皮纸上的内容后发现,里面书写的古代人一直没能解出的难题, 解除这道题目的人只要将答案用石笔写到这张羊皮纸上就能到达王室的宝藏室了。而当小 FF 拿起石笔后,刚刚打开的巨石门突然关上了。 这时小 FF 意识到原来那几具骷髅是在他之前到这里的冒险者,恐怕是因为没能破解这道题而困死在这里了。 小 FF 越想越害怕, 急忙联系到了你,为了能保命,他甚至愿意和你五五分……看来你不得不再次帮他了。 羊皮纸上的问题如下:
已知 x, y 为整数,且满足以下两个条件:
1. x, y ϵ [1..k], 且x,y,k ϵ Z;
2. (x^2 – xy – y^2)^2 = 1
给你一个整数 k, 求一组满足上述条件的 x, y 并且使得 x^2 + y^2 的值最大。
当小 FF 得到答案后, 用石笔将答案书写在羊皮纸上,那么就能到达王室的遗产所在地了。输入
一个整数 k输出
输出文件仅一行,两个整数;
两个整数分别表示 x 和 y。x, y 之间用一个空格隔开。
样例输入
1995样例输出
1597 987数据范围限制
对于 30%的数据: 2<=k<=10^4.
对于 100%的数据: 2<=k<=10^18.
提示
Z是数学里面整数集合符号, 即x y k都是整数
该题最为简单 洛谷上有原题 入门难度
实现方法:打表!!!
最终打完表就发现:这不就是斐波那契数列的水题吗???(我在考场上都没想到)
证明过程:
(x2-xy-y2)2=1
原方程化为:(y2+xy-x2)2=1
((x+y)2-xy-2x2)2=1
((x+y)2-xy-x2-x2)2=1
((x+y)2-x(x+y)-x2)2=1
对比(x2-xy-y2)2=1 与((x+y)2-x(x+y)-x2)2=1,不难发现有x:y=x+y:x
这不就是斐波那契数列吗?
附上代码:(暴搜代码(TLE30分)+找规律的斐波那契代码(AC100分))
1 #include <cstdio> 2 #include <iostream> 3 #include <cmath> 4 #include <algorithm> 5 #define rr register 6 #define ll long long 7 using namespace std; 8 ll k; 9 int main() 10 { 11 //freopen("puzzle.in","r",stdin); 12 //freopen("puzzle.out","w",stdout); 13 scanf("%lld",&k); 14 for(rr ll i=k;i>=1;i--) 15 for(rr ll j=k;j>=1;j--) 16 { 17 if(i*i+j*j==1+2*j*j+i*j) 18 { 19 printf("%lld %lld",i,j); 20 return 0; 21 } 22 if(i*i+j*j==-1+2*j*j+i*j) 23 { 24 printf("%lld %lld",i,j); 25 return 0; 26 } 27 } 28 }
1 #include <cstdio> 2 long long a,b,c,k; 3 int main() 4 { 5 freopen("puzzle.in","r",stdin); 6 freopen("puzzle.out","w",stdout); 7 scanf("%lld",&k); 8 a=b=1; 9 while(a<=k) 10 { 11 c=a; 12 a=a+b; 13 b=c; 14 } 15 printf("%lld %lld",b,a-b); 16 }
第二题 【2265. 最接近神的人】
2265. 最接近神的人
(File IO): input:Sophist.in output:Sophist.out时间限制: 1000 ms 空间限制: 60000 KB 具体限制
题目描述
破解了符文之语,小 FF 开启了通往地下的道路。 当他走到最底层时, 发现正前方有一扇巨石门, 门上雕刻着一副古代人进行某种活动的图案。而石门上方用古代文写着“神的殿堂“。小FF 猜想里面应该就有王室的遗产了。但现在的问题是如何打开这扇门……
仔细研究后, 他发现门上的图案大概是说:古代人认为只有智者才是最容易接近神明的。 而最聪明的人往往通过一种仪式选拔出来。 仪式大概是指,即将隐退的智者为他的候选人写下一串无序的数字, 并让他们进行一种操作, 即交换序列中相邻的两个元素。 而用最少的交换次数使原序列变成不下降序列的人即是下一任智者。
小 FF 发现门上同样有着 n 个数字。于是他认为打开这扇门的秘诀就是找到让这个序列变成不下降序列所需要的最小次数。但小 FF 不会……只好又找到了你,并答应事成之后与你三七分……输入
第一行为一个整数 n,表示序列长度
第二行为 n 个整数,表示序列中每个元素。输出
一个整数 ans,即最少操作次数。样例输入
4 2 8 0 3样例输出
3 样例说明: 开始序列为 2 8 0 3, 目标序列为 0 2 3 8,可进行三次操作得目标序列: 1. Swap(8, 0): 2 0 8 3 2. Swap(2, 0): 0 2 8 3 3. Swap(8, 3): 0 2 3 8数据范围限制
对于 30%的数据 1 <= n <= 10^4.
对于 100%的数据 1 <= n <= 5 * 10^5;
-maxlongint <= A[i ]<= maxlongint .
洛谷原题 洛谷给的难度是普及+/提高这道题看上去完全没有头绪,把这道题看懂了以后就明白了,这道题的模型就是求
!!!逆数对!!!点我传送去逆数对详解
这道题就是求解逆数对的对数,可以用归并排序的方法求解,也可以用线段树求解(然而我并不会)。
附上代码(归并排序的代码直接搬上来的)100分AC
1 #include <cstdio> 2 long long answer=0,a[5*100005],r[5*100005]; 3 void msort(int s,int t) 4 { 5 if(s==t) return; 6 int mid=(s+t)/2; 7 msort(s,mid); 8 msort(mid+1,t); 9 int i=s,j=mid+1,k=s; 10 while(i<=mid && j<=t) 11 { 12 if(a[i]<=a[j]) 13 { 14 r[k]=a[i];k++;i++; 15 }else{ 16 r[k]=a[j];k++;j++; 17 answer+=mid-i+1; 18 } 19 } 20 while(i<=mid) 21 { 22 r[k]=a[i];k++;i++; 23 } 24 while(j<=t) 25 { 26 r[k]=a[j];k++;j++; 27 } 28 for(int i=s;i<=t;i++) a[i]=r[i]; 29 } 30 int main(){ 31 freopen("Sophist.in","r",stdin); 32 freopen("Sophist.out","w",stdout); 33 int n; 34 scanf("%d",&n); 35 for(int i=1;i<=n;i++) 36 scanf("%lld",&a[i]); 37 msort(1,n); 38 printf("%lld",answer); 39 }
第四题 【2267. 宝物筛选】
2267. 宝物筛选
(File IO): input:treasure.in output:treasure.out时间限制: 1000 ms 空间限制: 60000 KB 具体限制题目描述
终于,破解了千年的难题。小 FF 找到了王室的宝物室,里面堆满了无数价值连城的宝物……这下小 FF 可发财了,嘎嘎。但是这里的宝物实在是太多了,小FF 的采集车似乎装不下那么多宝物。 看来小 FF 只能含泪舍弃其中的一部分宝物了……小FF 对洞穴里的宝物进行了整理,他发现每样宝物都有一件或者多件。他粗略估算了下每样宝物的价值,之后开始 了宝物筛选工作:
小 FF 有一个最大载重为 W 的采集车, 洞穴里总共有 n 种宝物的,每种宝物的价值为v [i], 重量为 w[i], 每种宝物有 m[i]件。 小 FF 希望在采集车不超载的前提下,选择一些宝物装进采集车,使得它们的价值和最大。输入
第一行为 2 整数 N 和 W,分别表示宝物种数和采集车的最大载重。
接下来 n 行每行三个整数, 其中第 i 行第一个数表示第 i 类品价值, 第二个整数表示一件该类物品的重量, 第三个整数为该类物品数量。输出
输出仅一个整数ans, 表示在采集车不超载的情况下收集的宝物的最大价值。样例输入
4 20 3 9 3 5 9 1 9 4 2 8 1 3样例输出
47数据范围限制
对于 30%的数据: n <= ∑m[i] <= 10^4; 0 <= W <=10^3.
对于 100%的数据: n <= ∑m[i] <=10^5; 0<= W <=4 * 10^4;
1 <= n <= 100.
这道题一眼就可以看出是道DP,并且还是DP中经典的背包问题。这道题应该是普及-的啊,为什么洛谷给的却是提高+/省选-的难度呢?
原因就在数据范围限制里!!!对,你没看错“对于 100%的数据: n <= ∑m[i] <=10^5; 0<= W <=4 * 10^4;”4*10^4,朴素算法不用说O(N3)是绝对超时的,所以说这道题考的是优化。
!!!二进制优化!!!点我跳转到二进制优化的详解
附上代码(抄来的自己改了改,其实我也不会写)100分AC代码
1 #include <cstdio> 2 #define rr register 3 signed v[4*10005],w[4*10005]; 4 signed f[4*10005]; 5 signed n,m,nl; 6 signed max(int a,int b) 7 { 8 if(a>b) 9 return a; 10 return b; 11 } 12 signed main() 13 { 14 freopen("treasure.in","r",stdin); 15 freopen("treasure.out","w",stdout); 16 scanf("%d %d",&n,&m); 17 for(rr int i=1;i<=n;i++) 18 { 19 signed x,y,s,t=1; 20 scanf("%d%d%d",&y,&x,&s); 21 while(s>=t) 22 { 23 v[++nl]=x*t; 24 w[nl]=y*t; 25 s-=t; 26 t*=2; 27 } 28 v[++nl]=x*s; 29 w[nl]=y*s; 30 } 31 for(rr int i=1;i<=nl;i++) 32 for(rr int j=m;j>=v[i];j--) 33 f[j]=max(f[j],f[j-v[i]]+w[i]); 34 printf("%d",f[m]); 35 }
第一题 【1437. 符文之语】
1437. 符文之语
(File IO): input:minmax.in output:minmax.out时间限制: 1000 ms 空间限制: 60000 KB 具体限制题目描述
做过了乘积最大这道题,相信这道题也难不倒你。 已知一个数串,可以在适当的位置加入乘号(设加了k个,当然也可不加,即分成k+1个部分),设这k+1个部分的乘积(如果k=0,则乘积即为原数串的值)对m 的余数(即mod m)为x; 现求x能达到的最小值及该情况下k的最小值,以及x能达到的最大值及该情况下的k的最小值(可以存在x的最小值与最大值相同的情况)。
以下是{原题:符文之语}另一种题目描述,题意相同:
{ 当小 FF 来到神庙时,神庙已经破败不堪了。 但神庙的中央有一个光亮如新的石台。小 FF 走近石台,发现石台上有一个数串,而数串的上方刻着一串古老的符文之语。精通古符文之语的小 FF 不费吹灰之力就读懂了文章的意思, 其大意是:
对于石台上的一串数字,你可以在适当的位置加入乘号(设加了 k 个,当然也可不加, 即分成 k+1 个部分),设这 k+1 个部分的乘积(如果 k=0,则乘积即为原数串的值)对 m 的余数(即 mod m)为 x;
现求 x 能达到的最小值及该情况下 k 的最小值,以及 x 能达到的最大值及该情况下的 k 的最小值(可以存在 x 的最小值与最大值相同的情况)。
小 FF 还知道, 如果他找到了正确的答案,那么就可以通往神庙的下层了。但这个问题似乎不太好解决, 小FF 就找到了你,并答应找到财宝以后和你二八分(当然你拿二……)。}输入
第一行为数串,长度为n 满足2<=n<=1000,且数串中不存在0; 第二行为m,满足2<=m<=50。输出
四个数,分别为x的最小值 和 该情况下的k,以及x的最大值和 该情况下的k,中间用空格隔开。样例输入
4421 22样例输出
0 1 21 0数据范围限制
这道题正解是DP,用三维的F[i][j][k]表示状态,其中,i表示处理当前到了数字串的第i位,j表示前i个数中最后放置的一个乘号前的积mod m,k表示最后一个乘号后的那个数字。
仔细思考后便可以推出这样一组状态转移方程:
用F[][][]表示当前放了unknow个乘号.
当前位置不放乘号:F[i+1][j][k*10+a[i+1]]=f[i][j][k];
当前位置放乘号:F[i+1][j*k mod m][a[i+1]]=f[i][j][k]+1;
然后就枚举i,j,k就可以了.
最小x值即这个DP中最小合法j值(即被DP到过的j值),在该x值下的最小k值即那个含有最小合法j值的状态的值(即F[unknow][最小合法j值][unknown])。
同理,最大x值即这个DP中最大合法j值(即被DP到过的j值),在该x值下的最小k值即那个含有最大合法j值的状态的值(即F[unknow][最大合法j值][unknown])。
代码:
1 //以后再发。(不用想了,等不到的咕咕咕)
End