Begin
(题目的排序方式:难易程度)
什么是对拍:
对拍是一种在写完程序后,验证自己程序是不是正解的比较方便的方法.
实现过程:
对同一道题,再打一个暴力程序,然后用一些大数据等跑暴力程序来进行验证,通过和自己写的程序的输出进行比较来查错。
2019.08.04【NOIP普及组】模拟赛C组
(就一道入门难度,其他就是1道普及+提高,2道提高+省选-。那还是人吗?普及模拟考这么难???想给出题人寄刀片)
第三题 【2266. 古代人的难题】
2266. 古代人的难题
(File IO): input:puzzle.in output:puzzle.out时间限制: 1000 ms 空间限制: 60000 KB 具体限制
该题最为简单 洛谷上有原题 入门难度
实现方法:打表!!!
最终打完表就发现:这不就是斐波那契数列的水题吗???(我在考场上都没想到)
证明过程:
(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 具体限制
洛谷原题 洛谷给的难度是普及+/提高这道题看上去完全没有头绪,把这道题看懂了以后就明白了,这道题的模型就是求
!!!逆数对!!!点我传送去逆数对详解
这道题就是求解逆数对的对数,可以用归并排序的方法求解,也可以用线段树求解(然而我并不会)。
附上代码(归并排序的代码直接搬上来的)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 具体限制
这道题一眼就可以看出是道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 具体限制
这道题正解是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