NOIP普及组复赛解题报告

合集下载

NOIP2023普及组解题报告

NOIP2023普及组解题报告

NOIP2023普及组解题报告1. 题目背景NOIP(全国青少年信息学奥林匹克竞赛)是中国最重要的信息学竞赛之一,旨在选拔出优秀的信息学人才。

本文将解析NOIP2023普及组的题目并给出详细的解题思路。

2. 题目描述题目一:数找数给定一组数字,从中选择出两个数字,它们的和正好等于给定的目标数。

假设给定的数字集合中只有一组解。

请编写程序找出这两个数字并输出其下标。

输入: - 第一行为一个整数n,表示数字的个数。

- 第二行为n个以空格分隔的整数,表示一组数字。

- 第三行为一个整数target,表示目标数。

输出: - 输出两个整数i和j,表示所选数字的下标(从1开始计数,索引间以空格分隔)。

题目二:矩阵变换给定一个大小为n x m的矩阵,请编写程序将其顺时针旋转90度。

输入: - 第一行为两个正整数n和m,表示矩阵的行数和列数。

- 接下来的n行为矩阵的元素,每行包含m个以空格分隔的数字。

输出: - 输出顺时针旋转后的矩阵,每行包含n个以空格分隔的数字。

题目三:字符串缩写给定一个字符串,请编写程序将其缩写。

输入: - 输入为一行字符串,长度不超过100个字符。

- 字符串中只包含英文小写字母。

输出: - 输出为缩写后的字符串。

3. 解题思路题目一:数找数本题通过使用两个指针,一个指向数组开始,一个指向数组末尾,不断向内扩展判断两个指针对应的数字之和与目标数的大小关系,直到找到解为止。

具体步骤如下:1.定义两个指针left和right,初始时分别指向数组的第一个和最后一个元素。

2.循环执行以下步骤:–如果left和right对应的数字之和等于目标数,则输出left+1和right+1,结束循环。

–如果left和right对应的数字之和大于目标数,则将right 向左移动一位。

–如果left和right对应的数字之和小于目标数,则将left 向右移动一位。

题目二:矩阵变换本题的思路是将原矩阵逐个读入,并按照顺时针旋转的规律重新输出。

NOIP2010普及组解题报告

NOIP2010普及组解题报告

NOIP2010普及组复赛解题报告(pascal)---------By 锦云第一题:two.pas本题没有什么技术含量,主要有三种方法:1.用枚举(找范围再分别处理,很麻烦)2.用分解(一步步分解,较简便)3.用先转换成字符串再做(很简便)参考程序:(在此只提供第二种解法的分解部分和第三种解法)第二种:Function fjtwo(a:integer):integer;Var cnt,tmp:integer;BeginCnt:=0;While a>0 doBeginTmp:=a mod 10;If tmp=2 then inc(cnt);Tmp:=tmp div 10;End;Fjtwo:=cnt;End;第三种:Var s:string;L,r,i,j,cnt:integer;BeginAssign(input,’two.in’);reset(input);Assign(output,’two.out’);rewrite(output);Readln(l,r);Cnt:=0;For i:=l to r doBeginString(I,s);For j:=1 to length(s) doIf s[i]=’2’ then inc(cnt);End;Writeln(cnt);Close(input);Close(output);End.第二题:water.pas本题主要是考验考生们的细心程度,从而找到最佳方案。

想了一想,本题采用模拟法,于是有了加或者减的方法。

1.减法(纯粹模拟)2.加法(更优模拟)注:减法时最好不要时间一点一点的模拟,找最小得数减。

参考程序:(本题提供较简单的写法加法)Var a:array[1..10000] of integer;N,mI,j,k:longint;BeginAssign(input,’water.in’);reset(input);Assign(output,’water.out’);rewrite(output);Readln(n,m);For i:=1 to n doRead(a[i]);For i:=m+1 to n doBeginK:=1;For j:=1 to m doIf a[j]<a[k] then k:=j;Inc(a[k],a[i]);End;K:=1;For i:=1 to m doIf a[i]>a[k] then k:=I;Writeln(a[k]);Close(input);Close(output);End.第三题:missile.pas本题实在是很难解决,n最大可以达到100000,而最优解的算法可以用搜索,但是n太大时,时间肯定不行,只好退而求其次,用贪心算法(无法得最优解但有70分,很不错了)参考程序:(贪心)Var l,n,x1,y1,x2,y2,tmpx,tmpy,max1,max2,jg1,jg2:longint;beginassign(input,'missile.in');reset(input);assign(output,'missile.out');rewrite(output);readln(x1,y1,x2,y2);readln(n);max1:=0;max2:=0;for i:=1 to n dobeginreadln(tmpx,tmpy);jg1:=sqr(abs(tmpx-x1))+sqr(abs(tmpy-y1));jg2:=sqr(abs(tmpx-x2))+sqr(abs(tmpy-y2));if (jg1>max1)and(jg2>max2) then if jg1<jg2 then max1:=jg1else max2:=jg2;end;writeln(max1+max2);close(input);close(output);end.第三题:解答本题,必须看清题意,知道以下几点:一、只需要选两次,由于比胜负靠的是双方武将中默契值最大的一对,所以除了默契值最大的一对,其他的武将都是没用的。

NOIP2009普及组复赛试题解题报告

NOIP2009普及组复赛试题解题报告

NOIP2009xx组复赛试题解题报告xx1、多项式输出本题只是一个基本知识点考核的一个题目,主要是看参赛选手的细心程度,无算法体现。

先定义一个系数的数组a[105]。

首先这一题解题的大的方向需要考虑两点,多项式系数a[i]大于零和小于零两种情况,因为系数为零时不输出该项,而大于零的要求输出含有“+”号,小于零的直接输出。

然后在分项进行处理:第一项要单独处理,在处理第一项时有3种情况如下:If (a[i]==1)Else if (a[i]==-1)Else if (a[i]!=0)接着对第二项到第n-1项进行处理这里在循环里面处理又有(a[i]>0 && a[i]!=1)(a[i]==1)(a[i]<0&& a[i]!=-1)(a[i]==-1)这四种情况分别讨论。

然后对a[n-1]项进行处理,同上面的循环里的处理方法只要注意幂指数为1的时候不需要输出就可以了,省略幂指数。

最后对常数项处理,分两种情况,a[n]>0和a[n]<0两种情况分别讨论最终即可解出本题。

参考程序如下:#include"stdio.h"main(){FILE *fin,*fout;int i,a[105],n;fin=fopen("poly.in","r");fout=fopen("poly.out","w");fscanf(fin,"%d",&n);for(i=0;i<=n;i++)fscanf(fin,"%d",&a[i]);if(a[0]==1)fprintf(fout,"x^%d",n);else if(a[0]==-1)fprintf(fout,"-x^%d",n);else if (a[0]!=0)fprintf(fout,"%dx^%d",a[0],n);for(i=1;i<n-1;i++){if(a[i]>0 && a[i]!=1) fprintf(fout,"+%dx^%d",a[i],n-i);if (a[i]==1)fprintf(fout,"+x^%d",n-i);if(a[i]<0 && a[i]!=-1)fprintf(fout,"%dx^%d",a[i],n-i);if (a[i]==-1)fprintf(fout,"-x^%d",n-i);}if(a[n-1]>0 && a[n-1]!=1)fprintf(fout,"+%dx",a[n-1]);if(a[n-1]==1)fprintf(fout,"+x");if(a[n-1]<0&&a[n-1]!=-1)fprintf(fout,"%dx",a[n-1]);if(a[n-1]==-1)fprintf(fout,"-x");if(a[n]>0)fprintf(fout,"+%d",a[n]);if(a[n]<0)fprintf(fout,"%d",a[n]);fclose(fin);fclose(fout);}2、分数线划定本题就是一个基本的简单排序题目,由于数据范围比较小,不需要用到快排或者其他排序,只要会一种基本的排序即可,比如用最熟悉的冒泡就可以完成该题的所有测试数据。

NOIP2008普及组复赛解题报告

NOIP2008普及组复赛解题报告

NOIP2008普及组复赛解题报告一、ISBN号码基础字符串处理题,心细一点的基本都能得满分。

参考程序:program isbn;constinp='isbn.in';oup='isbn.out';vari,j,k,ans:longint;s:string;ch:char;procedure flink;beginassign(input,inp);reset(input);assign(output,oup);rewrite(output);end;procedure fclose;beginclose(input);close(output);end;beginflink;readln(s);// 输入字符串j:=0;i:=1;ans:=0;while j<9 dobeginif s[i] in ['0'..'9'] then//如果是数字,那么累加到ans中,共9个数字begininc(j);inc(ans,(ord(s[i])-ord('0'))*j);end;inc(i);end;ans:=ans mod 11;计算识别码if ans=10 then ch:='X' else ch:=chr(ord('0')+ans);//把识别码转换成字符,方便输出if s[length(s)]=chthen write('Right')else write(copy(s,1,12)+ch);//输出正确的识别码fclose;end.二、排座椅用的是赛前集训时提到的贪心,当时说某些题目用贪心可以得部分分,但是本题贪心可以得满分的。

当然本题的贪心需要预处理下,开2个一维数组,row[i]录如果在第i行加通道,可以分割多少对调皮学生,col[i]记录如果在第j列加通道,可以分割多少对调皮学生,最后贪心法输出分割学生最多的前K行和前L列。

NOIP20XX普及组复赛试题与解题报告

NOIP20XX普及组复赛试题与解题报告

NOIP20XX普及组复赛试题与解题报告NOIP 20XX普及组解题报告一、ISBN号码【问题描述】每一本正式出版的图书都有一个ISBN号码与之对应,ISBN码包括9位数字、1位识别码和3位分隔符,其规定格式如“x-xxx-xxxxx-x”,其中符号“-”是分隔符,最后一位是识别码,例如0-670-82162-4就是一个标准的ISBN码。

ISBN码的首位数字表示书籍的出版语言,例如0代表英语;第一个分隔符“-”之后的三位数字代表出版社,例如670代表维京出版社;第二个分隔之后的五位数字代表该书在出版社的编号;最后一位为识别码。

识别码的计算方法如下:首位数字乘以1加上次位数字乘以2……以此类推,用所得的结果mod 11,所得的余数即为识别码,如果余数为10,则识别码为大写字母X。

例如ISBN号码0-670-82162-4中的识别码4是这样得到的:对067082162这9个数字,从左至右,分别乘以1,2,…,9,再求和,即0×1+6×2+……+2×9=158,然后取158 mod 11的结果4作为识别码。

你的任务是编写程序判断输入的ISBN号码中识别码是否正确,如果正确,则仅输出“Right”;如果错误,则输出你认为是正确的ISBN号码。

【输入】输入文件只有一行,是一个字符序列,表示一本书的ISBN号码。

【输出】输出文件共一行,假如输入的ISBN号码的识别码正确,那么输出“Right”,否则,按照规定的格式,输出正确的ISBN号码。

【输入输出样例1】 0-670-82162-4Right【输入输出样例2】0-670-82162-00-670-82162-4【试题分析】基础字符串处理题,心细一点的基本都能得满分。

【参考程序】 program isbn; constinp=''; oup=''; vari,j,k,ans:longint; s:string; ch:char; procedure flink; beginassign(input,inp);reset(input); assign(output,oup); rewrite(output); end;procedure fclose; beginclose(input); close(output); end; begin flink;readln(s);// 输入字符串 j:=0;i:=1; ans:=0; while jk do inc(i); while tmp[j]j;if m0 then begin inc(j);tmp[j]:=row[i]; end; end;qsort(1,j);//对tmp数组排序flag:=tmp[k];//flag为前K项的最小值 i:=1;j:=0;while (i=flag then //如果该行能分割的人数不少于flag,说明此处可以添加通道 begin write(i); inc(j);if jk then write(' '); end; inc(i); end; writeln;//下面是求列通道,思想同上j:=0;for i:= 1 to n do beginif col[i]>0 then begin inc(j);tmp[j]:=col[i]; end; end; qsort(1,j); flag:=tmp[L]; i:=1; j:=0;while (i=flag then begin write(i); inc(j);if jL then write(' '); end; inc(i); end;fclose; end.三、传球游戏【问题描述】上体育课的时候,小蛮的老师经常带着同学们一起做游戏。

NOIP2012普及组复赛解题报告c++版本

NOIP2012普及组复赛解题报告c++版本

信息学奥赛NOIP2012普及组解题报告(c++版本)第一题质因数分解, 题目已知正整数n是两个不同的质数的乘积, 试求出较大的那个质数, 没什么技术含量, 直接开个根号搜一遍就好了. 另外不开根号会TLE导致得60分.1 #include <stdio.h>2 #include <math.h>3int main()4 {5int n;6scanf("%d", &n);7for (int i = 2, k = sqrt(n) + 1; i < k; ++i)8if (n % i == 0)9{10printf("%d\n", n / i);11break;12}13return0;14 }第二题寻宝[题目]传说很遥远的藏宝楼顶层藏着诱人的宝藏。

小明历尽千辛万苦终于找到传说中的这个藏宝楼,藏宝楼的门口竖着一个木板,上面写有几个大字:寻宝说明书。

说明书的内容如下:藏宝楼共有N+1层,最上面一层是顶层,顶层有一个房间里面藏着宝藏。

除了顶层外,藏宝楼另有N层,每层M个房间,这M个房间围成一圈并按逆时针方向依次编号为0,…,M-1。

其中一些房间有通往上一层的楼梯,每层楼的楼梯设计可能不同。

每个房间里有一个指示牌,指示牌上有一个数字x,表示从这个房间开始按逆时针方向选择第x个有楼梯的房间(假定该房间的编号为k),从该房间上楼,上楼后到达上一层的k号房间。

比如当前房间的指示牌上写着2,则按逆时针方向开始尝试,找到第2个有楼梯的房间,从该房间上楼。

如果当前房间本身就有楼梯通向上层,该房间作为第一个有楼梯的房间。

寻宝说明书的最后用红色大号字体写着:“寻宝须知:帮助你找到每层上楼房间的指示牌上的数字(即每层第一个进入的房间内指示牌上的数字)总和为打开宝箱的密钥”。

请帮助小明算出这个打开宝箱的密钥。

这个题是个简单的模拟, 但是出乎意料的恶心, 当年做这个题的时候爆零, 钛蒻了, 总感觉这个比第三题难.1 #include <stdio.h>2int x[10003][103], fjx[103];3bool k[10003][103];4int main()5 {6int n, m, s, t, key = 0, turn;7scanf("%d %d", &n, &m);8for (int i = 0, j; i < n; ++i)9for (j = 0; j < m; ++j)10scanf("%d %d", &k[i][j], &x[i][j]);11scanf("%d", &s);12key = 0;13for (int i = 0, j = s, h = 0, fj = 0; i < n; ++i)14{15key = (key + x[i][s]) % 20123;16while (h < m)17{18if (k[i][j] == 1)19fjx[fj++] = j;20++h;21++j;22if (j == m)23j = 0;24}25t = (x[i][s] - 1) % fj;26s = fjx[t];27}28printf("%d\n", key);29return0;30 }第三题摆花[题目]小明的花店新开张,为了吸引顾客,他想在花店的门口摆上一排花,共m盆。

noip2009复赛普及组解题报告

noip2009复赛普及组解题报告

noip2009复赛普及组解题报告多项式输出问题转述:给出一个一元多项式各项的次数和系数,按照规定的格式要求输出该多项式。

分析:普及组的水题。

多项式大家应该很熟悉,输出的时候注意一下几点即可:1. 最高次项为正的话开头无加号。

2. 系数为0不输出。

3. 一次项输出x,并非x^1。

4. 非常数项系数为1或-1时直接输出正负号,但是常数项需要输出该数字。

其中除第三项外其它均可在样例中检查出错误,但是若没想到第三点那么就只能得到50分了。

程序:var i,k,n:longint;beginassign(input,'poly.in');reset(input);assign(output,'poly.out');rewrite(output);readln(n);for i:=n downto 0 dobeginread(k);if k=0 then continue;if (k>0) and (i<>n) then write('+');if i=0 then write(k)else if (abs(k)<>1) then write(k) else if k=-1 then write('-');if i<>0 thenif i=1 then write('x')else write('x^',i);end;writeln;close(input);close(output);end.---------------------------------------------------------------------分数线划定问题转述:给出录取人数及所有面试者成绩,考号。

求出分数线和实际录取人数,并按成绩降序,若成绩相同则考号升序的规则输出录取人考号与成绩。

全国信息学奥林匹克联赛(NOIP2010)复赛_普及组_解题报告(pascal)

全国信息学奥林匹克联赛(NOIP2010)复赛_普及组_解题报告(pascal)

全国信息学奥林匹克联赛(NOIP2010)复赛_普及组_解题报告(pascal)全国信息学奥林匹克联赛(NOIP2010)复赛普及组解题报告1.数字统计(two.pas/c/cpp)【问题描述】请统计某个给定范围[L, R]的所有整数中,数字2 出现的次数。

比如给定范围[2, 22],数字2 在数2 中出现了1 次,在数12 中出现1 次,在数20 中出现1 次,在数21 中出现1 次,在数22 中出现2 次,所以数字2 在该范围内一共出现了6次。

【算法思路】枚举法,依次将L至R转化为字符串,查找当中有多少个”2”.【程序代码】program two;varl,r:1..10000;i,j,h,c:longint;s:string;beginassign(input,'two.in');assign(output,'two.out');reset(input);rewrite(output);readln(l,r);c:=0;for i:=l to r dobeginstr(i,s);h:=length(s);for j:=1 to h doif s[j]='2'then c:=c+1;end;writeln(c);close(input);close(output);end.2.接水问题(water.pas/c/cpp)【问题描述】学校里有一个水房,水房里一共装有m 个龙头可供同学们打开水,每个龙头每秒钟的供水量相等,均为1。

现在有n 名同学准备接水,他们的初始接水顺序已经确定。

将这些同学按接水顺序从1到n 编号,i号同学的接水量为w i。

接水开始时,1 到m 号同学各占一个水龙头,并同时打开水龙头接水。

当其中某名同学j 完成其接水量要求w j 后,下一名排队等候接水的同学k马上接替j 同学的位置开始接水。

这个换人的过程是瞬间完成的,且没有任何水的浪费。

NOIP2009普及组复赛解题报告

NOIP2009普及组复赛解题报告

NOIP2009普及组复赛解题报告NFLS QMD第一题多项式输出1、摘要时间复杂度:O(n)空间复杂度:O(n)2、题目大意输入一个n次多项式各项的系数,按要求输出多项式3、算法分析先将不为0的系数和对应的次数存入a数组和b数组,然后依次输出。

要注意以下几点:①系数绝对值为1的情况②指数为1或0的情况③首项加号不必输出4、参考程序program poly;varn,i,g,xx:integer;a,b:array[0..200]of integer;function x(n:integer):string; //处理项的x^n部分varst1:string;beginif n=0 then x:='';if n=1 then x:='x';if n>1 thenbeginstr(n,st1);x:='x^'+st1;end;end;procedure flag(t:integer); //处理每项的符号beginif t>0 then write('+')else write('-');end;beginassign(input,'poly.in');reset(input);assign(output,'poly.out');rewrite(output);readln(n);g:=0;for i:=n downto 0 do //保存系数非零的项beginread(xx);if xx<>0 thenbeging:=g+1;a[g]:=xx;b[g]:=i;end;end;for i:=1 to g dobeginif i=1 then //处理首项的情况beginif abs(a[1])>1 then write(a[1]);if a[1]=-1 then write('-');endelsebeginflag(a[i]);if(b[i]=0)or(abs(a[i])<>1)then write(abs(a[i])); end;write(x(b[i]));end;writeln;close(input);close(output);end.第二题分数线划定1、摘要核心算法思想:排序时间复杂度:O(Nlog2N)空间复杂度:O(N)2、题目大意给出n个分数和编号(编号互不相同),按分数从大到小取前[m*150%]个(可能有重分情况),输出实际数目,最低分数以及按顺序排列的分数、编号。

NOIP普及组解题分析报告

NOIP普及组解题分析报告

NOIP普及组解题报告————————————————————————————————作者:————————————————————————————————日期:NOIP2014普及组复赛解题报告本人是潍坊一中的wyw,69级,今年高一,现在马上就要NOIP了,打算把历年的NOIP普及、提高组题目都做一下,然后写写解题报告∵这个报告主要是给初中同学看的,所以我会写的详细一点Prolem 1 珠心算测试(count)这道题其实很简单,意思就是说给你一些数a1,a2,a3,a4...a n,然后让你回答有多少个A+B=C(A ≠ B ≠ C)满足(回答C的数量,而不是等式的数量)方法一那么有一种很明显的做法就是三层循环枚举C、A、B,注意:C是在最外层,若找到了一个A和一个B,满足上述等式,则C是一个符合要求的解,这时ans++,并且退出当前枚举,枚举下一个C,这种算法的时间复杂度是O(N3)而我当时没想到这个算法,因为有更好用而且简单更不容易出错的解法,方法二两重循环,分别枚举i=1...n,j=i+1...n,如果ai+aj这个数在集合中存在,那么you[a i+a j]←true,然后再从a1到a n做一次扫描,只要you[a i],ans++这个算法的好处在于它很好写,不用退出什么的,也不用注意循环的顺序,而且时间复杂度是O(N2)代码(方法2):#include<cstdio>using namespace std;int n, a[101], i, j, count;bool you[20001]={false};int main(){freopen("count.in","r",stdin);freopen("count.out","w",stdout);scanf("%d",&n);for(i=1;i<=n;i++)scanf("%d",&a[i]);for(i=1;i<n;i++)for(j=i+1;j<=n;j++)you[ a[i]+a[j] ]=true;count=0;for(i=1;i<=n;i++)count += you[ a[i] ];printf("%d\n",count);return 0;}在此征求一下大神的意见,如有更快的做法,敬请奉上小结:这道题很简单,但很多人没有做对的原因就是没有好好理解题意,但是根本原因其实还在于心态太骄傲了,认为是第一题就可以轻视,这样是不好的,水题我们更要做好啊,你想想同样是100分,这100分多么好拿,所以是水题、越该放平心态,细心地做。

NOIP2017复赛(普及组)解题报告!

NOIP2017复赛(普及组)解题报告!

NOIP2017复赛(普及组)解题报告!定期推送帐号信息学新闻,竞赛自主招生,信息学专业知识,信息学疑难解答,融科教育信息学竞赛培训等诸多优质内容的微信平台,欢迎分享文章给你的朋友或者朋友圈!1.成绩(score.cpp/c/pas)【问题描述】牛牛最近学习了 C++入门课程,这门课程的总成绩计算方法是:总成绩=作业成绩×20%+小测成绩×30%+期末考试成绩×50%牛牛想知道,这门课程自己最终能得到多少分。

【输入格式】输入文件名为 score.in。

输入文件只有 1 行,包含三个非负整数A、B、C,分别表示牛牛的作业成绩、小测成绩和期末考试成绩。

相邻两个数之间用一个空格隔开,三项成绩满分都是 100 分。

【输出格式】输出文件名为 score.out。

输出文件只有 1 行,包含一个整数,即牛牛这门课程的总成绩,满分也是 100 分。

【输入输出样例 1】score.in100100 80score.out90【输入输出样例 2】score.in60 90 80score.out79【数据说明】对于 30% 的数据,A=B=0。

对于另外 30% 的数据,A = B = 100。

对于 100% 的数据,0 ≤ A、B、C ≤ 100且 A、B、C 都是 10 的整数倍。

#includeusing namespace std;int a,b,c;int main(){cin>>a>>b>>c;a/=5;b=b*3/10;c/=2;cout<><>return 0;}2. 图书管理员 (librarian.cpp/c/pas)【问题描述】图书馆中每本书都有一个图书编码,可以用于快速检索图书,这个图书编码是一个正整数。

每位借书的读者手中有一个需求码,这个需求码也是一个正整数。

如果一本书的图书编码恰好以读者的需求码结尾,那么这本书就是这位读者所需要的。

第十一届全国青少年奥林匹克信息学联赛复赛普及组解题报告与参考程序

第十一届全国青少年奥林匹克信息学联赛复赛普及组解题报告与参考程序

第十一届全国青少年奥林匹克信息学联赛复赛普及组解题报告与参考程序(circle)program circlexe;constlmax=100;typeart=array[0..lmax]of integer;vardata,sour,targ,time,again,mid:art;fg:art;fi,fo:text;st:string;i,j,k,t,p:integer;procedure input;vari,j,x,len:integer;beginassign(fi,'circle.in');reset(fi);assign(fo,'circle.out');rewrite(fo);read(fi,st);x:=pos(' ',st);len:=length(st);val(copy(st,x+1,len-x),k,i);st:=copy(st,1,x-1);len:=length(st);if k>len then k:=len;for i:=1 to k dodata[i]:=ord(st[len-i+1])-ord('0');close(fi);end;procedure init(a:art;var b:art);vari:integer;beginfor i:=1 to k dob[i]:=a[i];end;procedure prnt;varp,i:integer;beginp:=lmax;while time[p]=0 dodec(p);for i:=p downto 1 dowrite(fo,time[i]);close(fo);end;procedure addtime(a:integer;var time:art);vari,x:integer;beginx:=0;for i:=1 to lmax dobegintime[i]:=a*time[i]+x;x:=time[i] div 10;time[i]:=time[i] mod 10;end;end;function multiply(a,b:art):art;vard,c:art;i,j,p,x:integer;beginfillchar(d,sizeof(d),0);for i:=1 to k dobeginif b[i]<>0 then beginp:=0;for j:=1 to k-i+1 dobeginx:=d[i+j-1]+a[j]*b[i]+p;p:=x div 10;d[i+j-1]:=x mod 10;end;end;end;multiply:=d;end;begininput;init(data,again);time[1]:=1;for i:=1 to k dobeginfillchar(fg,sizeof(fg),0);p:=data[i];fg[p]:=1;t:=1;init(data,sour);for j:=1 to 10 dobegintarg:=multiply(sour,again);p:=targ[i];if fg[p]=0 then beginfg[p]:=1;init(targ,sour);inc(t);endelse if p<>data[i]then beginwrite(fo,-1);close(fo);halt;endelse break;end;fillchar(mid,sizeof(mid),0);mid[1]:=1;for j:=1 to t domid:=multiply(mid,again);init(mid,again);addtime(t,time);end;prnt;end.。

NOIP普及组解题报告

NOIP普及组解题报告

NOIP2006复赛普及组解题报告【第一题解题思想】:这道题属于容易题,但是题目难度大于NOIP2005和2004普及组第一题,和去年第二题难度相当后者略低一些。

解法1:我们可以用先去掉重复(读入第i个数,和他前面的i-1个数比较),然后用简单排序和冒泡排序排序,最后输出结果。

解法2:运用插入排序(略加修改),边排序边除掉重复。

解法3:直接排序,不去掉重复,计算出不重复的元素个数,输出不重复的元素即可。

如果用数组A存储这些随机数,对于2到N个元素需要比较A是否等于A[i-1]。

解法4:开一个1到1000初值均为假的布尔数组A。

用整型变量X读入N个随机数,赋A[X]的值为真。

统计数组中值为真的元素个数即M,从i从1到1000输出A值为真的i。

这种方法可以算作哈希表的简单应用。

解法5:很多人想到排序,效率大概是O(n^2)吧,其实还有个更简单的方法。

用一个1到1000的数组储存每个数的出现情况,t每出现一次,a[t]=a[t]+1,而且,同时操作 if(a[t]>1) 则总数=总数-1。

然后从1到1000的循环,如果a≠0,输出,这样就根本不用排序了。

大概这个应该是最优算法吧。

O(n)的效率。

program random(input,output);var a:array[1..1000] of integer; / ’a是记录数组,相当于数轴,与数一一对应,temp 是临时存储数据,n和题目一样,记录不相同的数的个数’/i,m,temp,n:integer;beginassign(input,'d:\data\random.in');reset(input);assign(output,'d:\data\random.out');rewrite(output);read(n);readln;fillchar(a,sizeof(a),0); /*初始化数组为0,pascal有fillchar*/m:=n;for i:=1 to n dobeginread(temp);a[temp]:=a[temp]+1; /*记录是哪个数*/if a[temp]>1 then dec(m);end;write(m);writeln;for i:=1 to 1000 doif a>0 then / *如果a不为0。

noip2003普及组复赛解题报告

noip2003普及组复赛解题报告

noip2003普及组复赛解题报告NOIP2003普及组复赛试题NOIP2003普及组复赛试题试题输入:苏州高斌大榕树题一、乒乓球(Table.pas)【问题背景】国际乒联现在主席沙拉拉自从上任以来就立志于推行一系列改革,以推动乒乓球运动在全球的普及。

其中11分制改革引起了很大的争议,有一部分球员因为无法适应新规则只能选择退役。

华华就是其中一位,他退役之后走上了乒乓球研究工作,意图弄明白11分制和21分制对选手的不同影响。

在开展他的研究之前,他首先需要对他多年比赛的统计数据进行一些分析,所以需要你的帮忙。

【问题描述】华华通过以下方式进行分析,首先将比赛每个球的胜负列成一张表,然后分别计算在11分制和21分制下,双方的比赛结果(截至记录末尾)。

比如现在有这么一份记录,(其中W 表示华华获得一分,L表示华华对手获得一分):WWWWWWWWWWWWWWWWWWW WWWLW在11分制下,此时比赛的结果是华华第一局11比0获胜,第二局11比0获胜,正在进行第三局,当前比分1比1。

而在21分制下,此时比赛结果是华华第一局21比0获胜,正在进行第二局,比分2比1。

如果一局比赛刚开始,则此时比分为0比0。

你的程序就是要对于一系列比赛信息的输入(WL形式),输出正确的结果。

【输入格式】每个输入文件包含若干行字符串(每行至多20个字母),字符串有大写的W、L和E组成。

其中E表示比赛信息结束,程序应该忽略E之后的所有内容。

【输出格式】输出由两部分组成,每部分有若干行,每一行对应一局比赛的比分(按比赛信息输入顺序)。

其中第一部分是11分制下的结果,第二部分是21分制下的结果,两部分之间由一个空行分隔。

【输入样例】WWWWWWWWWWWWWWWWWWWWWWLWE【输出样例】11:011:01:121:02:1题二、数字游戏(Game.pas)【问题描述】丁丁最近沉迷于一个数字游戏之中。

这个游戏看似简单,但丁丁在研究了许多天之后却发觉原来在简单的规则下想要赢得这个游戏并不那么容易。

NOIP2012普及组复赛解题报告

NOIP2012普及组复赛解题报告

第一题:筛选法求素数。

var a:array[1..50000]of boolean;x,y,i,j,n:longint;beginassign(input,'prime.in'); reset(input);assign(output,'prime.ans'); rewrite(output);readln(n);fillchar(a,sizeof(a),true);for i:=2 to trunc(sqrt(50000)) doif a[i] thenfor j:=2 to 50000 div i doa[i*j]:=false;for i:=2 to 50000 doif a[i] and (n mod i=0) thenbegin writeln(n div i); break; end;close(input); close(output);end.第二题:模拟法,因为指示牌上的数字较大,可先统计每层有楼梯的个数,再取余。

var a,b:array[0..10000,0..100]of longint; x,y,i,j,k,n,m,s,t,w:longint;c:array[1..10000]of integer;begin{ assign(input,'c:\1.in'); reset(input);}assign(input,'treasure.in'); reset(input);assign(output,'treasure.ans'); rewrite(output);readln(n,m);for i:=1 to n do begins:=0;for j:=0 to m-1 do beginreadln(a[i,j],b[i,j]);if a[i,j]=1 then s:=s+1;end;c[i]:=s;end;readln(x); s:=0;for i:=1 to n do beginy:=x; s:=(s+b[i,x])mod 20123; t:=b[i,x]mod c[i]+c[i];repeatif a[i,y]=1 then t:=t-1;if t=0 then break;y:=y+1;if y=m then y:=0;until false;x:=y;end;writeln(s); close(input); close(output);end.第三题:动态规划F[I,J] 表示用I种花摆J盆共有和摆法,则F[I,J]=(∑F[I-1,J] ),(注意只取J-I的盆数~J盆求和)var a:array[0..100,0..100]of longint;i,j,k,m,n,s,t:longint; w:array[0..100]of longint;beginassign(input,'flower.in'); reset(input);assign(output,'flower.ans'); rewrite(output);readln(n,m);for i:=1 to n do read(w[i]);for i:=1 to w[1] do a[1,i]:=1;for i:=0 to m do a[i,0]:=1;for i:=2 to m do beginfor j:=1 to m do begins:=0;for k:=j-w[i] to j doif k>=0 then s:=(s+a[i-1,k])mod 1000007;a[i,j]:=s;end;end;writeln(a[m,m]);close(input); close(output);end.4、搜索,可是第10个数据过不了,要输出“-1”,不知道哪里BUG了,不想了。

NOIP2013普及组复赛试题+解题报告

NOIP2013普及组复赛试题+解题报告

expr.out 4
【输入输出样例说明】 样例 1 计算的结果为 8,直接输出 8。 样例 2 计算的结果为 1234567891,输出后 4 位,即 7891。 样例 3 计算的结果为 1000000004,输出后 4 位,即 4。 【数据范围】 对于 30%的数据,0≤表达式中加法运算符和乘法运算符的总数≤100; 对于 80%的数据,0≤表达式中加法运算符和乘法运算符的总数≤1000; 对于 100%的数据,0≤表达式中加法运算符和乘法运算符的总数≤100000。
3
【数据范围】 对于 20%的数据,1 ≤ n, m ≤ 10; 对于 50%的数据,1 ≤ n, m ≤ 100; 对于 100%的数据,1 ≤ n, m ≤ 1000。
第 5 页共 5 页
NOIp2013 普及组 解题报告
By 绍兴文理学院附中 任轩笛
NOIp2013 普及组
解题报告
By 绍兴文理学院附中 任轩笛
第 2 页共 5 页
全国信息学奥林匹克联赛(NOIP2013)复赛
普及组
【输入输出样例 1】 expr.in 1+1*3+4
expr.out 8
【输入输出样例 2】 expr.in 1+1234567890*1
expr.out 7891
【输入输出样例 3】 expr.in 1+1000000003*1
第 4 页共 5 页
全国信息学奥林匹克联赛(NOIP2013)复赛
普及组
车站编号 车站级别 车次 1 2 3 4 5
1 3 始 始 → →
2 1 → → → →
3 2 停 始 → 始 → → → →
4 1 → → → 始 → → → → → →

NOIP2017普及组复赛-解题报告

NOIP2017普及组复赛-解题报告

NOIP2017普及组复赛-解题报告衢州市兴华中学By 冯明浩给出三个整十数A,B,C ,求A*20%+B*30%+C*50%的值模拟直接粗暴地输出A*0.2+B*0.3+C*0.5时间复杂度:O(1) 期望得分:100由于分数均为整十数,先将分数各除以10,再直接输A*2+B*3+C*5。

这样就避免了精度问题时间复杂度:O(1) 期望得分:100给出N 个数Ai ,再进行Q 次询问,找后缀为给定数Bi 的最小的Ai模拟将Ai 及Bi 都转化成字符串。

每次询问都对N 个数进行后缀比较,挑出个最小的时间复杂度:O(N*Q*len) 期望得分:80 对算法一的比较进行优化——构造出n 10,对于Ai ,直接Ai Mod 10len ,判断是否相等。

这样每次比较的时间复杂度优至O(1)同时先将Ai 排序,再每次从小到大查询,一旦找到就停时间复杂度:小于O(N*Q)(一般情况) 期望得分:100读入Ai 时进行处理,构造ans[x]数组,记录询问X 的最小值。

对于每个Ai ,依次取出其后1、2、3……len 位,修正其的最小值。

这样每次查询,就可以O (1)出结果了时间复杂度:O(N*len) 空间复杂度:O(max(Bi)) 期望得分:100给出一个N*N 的矩阵,其中部分格有颜色每次可以从一个格向上下左右四个方向移动一格(不能越出矩阵且满足条件),根据两个格子的颜色有不同的代价求从左上角走至右下角的最小代价最短路(动态规划)直接暴力地按照题意进行DFS时间复杂度:O(n n *2) 期望得分:30以左上角为起点,右下角为终点,刷四个方向的SPFA(也可预先对相邻格建好边,刷最短路SPFA 或DIJ 或进行记忆化DFS )时间复杂度:O(k*n*n) 期望得分:100给出N 个格子的位置Xi 与价值Pi ,从起点0往右跳跃,初始跳跃的距离只能为d同时可以花费金币来调整其跳跃距离,花了t 个金币时可跳跃的距离为max(1,d-t)~(d+k)每遍历一个格子就会获得其代价Pi ,求要获得总价值为K 所需最少的金币数二分、动态规划、单调序列(堆)从小到大枚举所需金币数,用O(N*N)的DP 进行check ,一旦发现可行就为答案时间复杂度:O(max(Ai)*N*N) 期望得分:20分析发现,枚举的金币数越多,跳跃范围越大,总价值一定越多——满足二分答案的单调性,于是将算法一的枚举答案变为二分枚举时间复杂度:O()max(2log Xi *N*N) 期望得分:50 分析一下DP 的转移方程:F[i]=max(F[j])+P[i](max(1,d-t)≤a[i]-a[j]≤d+k)就会发现DP 的j 这次循环是为了找F[1~i-1]中的最大值,自然而然就想到了用堆优化——堆中存放F[1~i-1],若堆顶距当前X[i]大于d+k ,就丢掉该元素(再也没用)否则若堆顶距当前X[i]小于max(1,d-t),就暂存在临时数组中,最后在当前解更新好后记得塞回去则F[i]=F[heap[1]]+P[i]时间复杂度:O()max(2log Xi *N*k*N 2log ) 期望得分:80 继续优化算法三的DP :那些离当前X[i]太近的实际上完全没有必要塞入堆中,那么再另开一个变量j 记录当前往堆中塞入的最后一个元素。

NOIP20XX普及组解题报告非官方

NOIP20XX普及组解题报告非官方

NOIP20XX 普及组解题报告非官方NOIP20XX 普及组解题报告-by 郑佳睿 1.成绩(/c/pas)【问题描述】最近学习了 C++入门课程,这门课程的总成绩计算方法是:总成绩=作业成绩X 20% +小测成绩X 30% +期末少分。

【输入格式】【输入样例2】60 90 80【输出样例2】79 【数据说明】30%的数据,A = B = 0对于另外30%的数据,A = B = 100。

对于 100% 的数据,0 < A 、B 、C < 100 且 A 、B 、C 都是10的整数倍。

【题解】超级水题,输入数据都是 10的倍数,不用考虑浮点的表示输入文件只有1行, 的作业成绩、小测个数之间用一个空格隔开, 入样例1】100 100 80包含三个非负整数 A 、B 、C 分别成绩和期末考试成绩。

相邻两 三项成绩满分都是100分。

【输 【输出样例1】90考试成绩X 50%问题,直接输出答案。

【代码】 #include using names pace std; inta,b,c; int main{ cin>>a>>b>>c;cout using names pace std; intn,q,a[1005]; int main{ cin>>n>>q;for(inti=1;i using names pace std; struct node{v=(a[x][y]==):+1; if(v>m >>n;memset(a,255,sizeof(a));//-1for(i nti=0;i>x>>y>>c;a[x][y]=c; } f[1][1]=0;for(inti=0;i>a[i];for(int j=0;j>len>>code;intx,y,c,can,v; //格点状态:坐标、临时颜色、能否用魔法、花费}cur;intn,m,ans;int a[105][105],f[105][105];//a为输入f 存储每格最小花费queue q;void exp and(intx,int y){ //该函数作用是扩展个格点int v;if((xm)||(ym)) return; // 越界忽略if(a[x][y]!=-1){//固有颜色花0个或1个金币空格0红色1黄色memset(f,127,sizeof(f));// 初值为 0x7f7f7f7f((node){1,1,a[1][1],1,0});for(inti=1;i using names pace std; struct node{v=(a[x][y]==):+1; if(v>m >>n;memset(a,255,sizeof(a));//-1for(i nti=0;i>x>>y>>c;while(! ){//广搜 cur= exp and(,);expan d(+1,); expan d(,);exp and(,+1); }if(f[m][m] usingnames pace std; inta,b,c;int main{ cin>>a>>b>>c;cout using names pace std; intn,q,a[1005];int main{ cin>>n>>q;for(inti=0;i>a[i];for(int j=0;j>len>>code;intx,y,c,can,v; //格点状态: 坐标、临时颜色、能否用魔法、花费}cur;intn,m,ans;int a[105][105],f[105][105];//a为输入f 存储每格最小花费queue q;void exp and(intx,int y){ //该函数作用是扩展个格点int v;if((xm)||(ym)) return; // 越界忽略if(a[x][y]!=-1){//固有颜色花0个或1个金币空格0红色1黄色memset(f,127,sizeof(f));//初值为 0x7f7f7f7fa[x][y]=c; } f[1][1]=0;((node){1,1,a[1][1],1,0});while(! ){ //广搜cur= exp and(,); expan d(+1,); expan d(,); expan d(,+1); }if(f[m][m]<20000) coutvvf[m][m]vve ndl; elsecoutvv-ivvendl; return 0; }4.跳房子(/c/pas)【问题描述】跳房子,也叫跳飞机,是一种世界性的儿童游戏,也是中国民间传统的体育游戏之一。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

NOIP2015 普及组解题报告南京师范大学附属中学树人学校CT1.金币(coin.cpp/c/pas)【问题描述】国王将金币作为工资,发放给忠诚的骑士。

第一天,骑士收到一枚金币;之后两天(第二天和第三天),每天收到两枚金币;之后三天(第四、五、六天),每天收到三枚金币;之后四天(第七、八、九、十天),每天收到四枚金币;这种工资发放模式会一直这样延续下去:当连续N天每天收到N枚金币后,骑士会在之后的连续N+1天里,每天收到N+1枚金币。

请计算在前K 天里,骑士一共获得了多少金币。

【输入格式】输入文件名为coin.in 。

输入文件只有1行,包含一个正整数K,表示发放金币的天数。

【输出格式】输出文件名为coin.out。

输出文件只有1 行,包含一个正整数,即骑士收到的金币数。

【数据说明】对于100%的数据,1 < K < 10,000【思路】模拟【时空复杂度】O(k) ,O(1)2 、扫雷游戏(mine.cpp/c/pas )【问题描述】扫雷游戏是一款十分经典的单机小游戏。

在n行m列的雷区中有一些格子含有地雷(称之为地雷格),其他格子不含地雷(称之为非地雷格)。

玩家翻开一个非地雷格时,该格将会出现一个数字——提示周围格子中有多少个是地雷格。

游戏的目标是在不翻出任何地雷格的条件下,找出所有的非地雷格。

现在给出n行m列的雷区中的地雷分布,要求计算出每个非地雷格周围的地雷格数。

注:一个格子的周围格子包括其上、下、左、右、左上、右上、左下、右下八个方向上与之直接相邻的格子。

【输入格式】输入文件名为mine.in 。

输入文件第一行是用一个空格隔开的两个整数n和m分别表示雷区的行数和列数。

接下来n行,每行m个字符,描述了雷区中的地雷分布情况。

字符’* '表示相应格子是地雷格,字符' ?'表示相应格子是非地雷格。

相邻字符之间无分隔符。

【输出格式】输出文件名为mine.out 。

输出文件包含n行,每行m个字符,描述整个雷区。

用’* '表示地雷格,用周围的地雷个数表示非地雷格。

相邻字符之间无分隔符。

【数据说明】对于100% 的数据,1< n W 1Q01< me 100【思路】模拟【技巧】可将数组多开一圈,省去边界条件的判断【时空复杂度】O(mn),O(mn)3. 求和(sum.cpp/c/pas)【问题描述】一条狭长的纸带被均匀划分出了n个格子,格子编号从1到n。

每个格子上都染了一种颜色color i(用[1,m]当中的一个整数表示),并且写了一个数字number i。

定义一种特殊的三元组:(x, y, z),其中x,y,z都代表纸带上格子的编号,这里的三元组要求满足以下两个条件:1.x, y, z 者E是整数,x < y < 乙y ? x = z ? y2.color x=color z满足上述条件的三元组的分数规定为(x+z)*(number x+number z)。

整个纸带的分数规定为所有满足条件的三元组的分数的和。

这个分数可能会很大,你只要输出整个纸带的分数除以10,007所得的余数即可。

【输入格式】输入文件名为sum.in。

第一行是用一个空格隔开的两个正整数n 和m,n 代表纸带上格子的个数,m 代表纸带上颜色的种类数。

第二行有n个用空格隔开的正整数,第i个数字number代表纸带上编号为i的格子上面写的数字。

第三行有m个用空格隔开的正整数,第i个数字color i代表纸带上编号为i的格子染的颜色。

【输出格式】输出文件名为sum.out。

共一行,一个整数,表示所求的纸带分数除以10,007所得的余数。

【数据说明】对于第1组至第2组数据,i<n<ioo,im^5对于第3组至第4组数据,i<n<3000,im x 100对于第5组至第6组数据,1<n< 100000,1m w 100000且不存在出现次数超过20 的颜色;对于全部10 组数据,1W n <100000, 1<m <100000, 1 <color i<m, 1 W n umber<100000【思路】先分析一下,我们的任务是什么。

题目的要求是求分数和,我们就得把所有符合条件的三元组“找”出来。

至少需要枚举三元组(x,y,z)中的一个元素,这里枚举的是z (当然x也可以,不过不要选y,因为y对分数没什么用)。

1、因为x<y<z,所以只需向前枚举x,y2、因为y-x二z-y,所以x+z=2y,x、z同奇偶,且分数与y无关,只需枚举z 和x。

3、因为colour x=colour z,所以只需枚举z之前同奇偶且同色的X。

这样的话时间复杂度是O(n2),能得40分。

如何快速枚举x呢?其实不是快速枚举x,是快速枚举分数和。

观察三元组分数:(x+z) • (number x+ number z)显然我们不方便处理多项式乘法,那就把它拆开(事实上很多人到这步都放弃了,其实试一试立刻就明白了)=x • number x+x • number z+z • numbei x+z • number z那么对于z的所有合法决策x1,x2, (x)根据乘法分配率,分数二艺(xi*number xi)+ 艺(xi)*number z + 艺(number x i) *z+ 艺(z*number z) (1<=i<=k)由于z是枚举的,所以只需快速得到艺(x • number x),艺x,艺number x和k (注意最后一项被算了k 次,要乘k)这样我们就可以开4 个累加器,分别记录这四个量。

而对于不同奇偶性、不同颜色的z有不同的决策x,所以要开一个s[2][m][4]的累加器。

【时空复杂度】O(n), O(n+m)【注意】题目数据较大,每次计算一定要模10007,否则很容易出错【样例程序】#include <cstdio>const int maxn=100000;const int maxm=100000;const int p=10007;int n,m,ans;int number[maxn+1],colour[maxn+1];int s[2][maxm+1][4];void init(){freopen("sum.in","r",stdin);freopen("sum.out","w",stdout);scanf("%d%d",&n,&m);for(int i=1;i<=n;i++)scanf("%d",&number[i]);for(int i=1;i<=n;i++)scanf("%d",&colour[i]);}void solve(){for(int i=1;i<=n;i++){int z=i%p,numz=number[i]%p,c=colour[i],t=i%2; intcount=s[t][c][0]%=p,x=s[t][c][1]%=p,numx=s[t][c][2]%=p,x_numx=s[t][c][3]%=p;ans=(ans+((count*z)%p*numz)%p)%p;ans=(ans+x_numx)%p;ans=(ans+x*numz)%p;ans=(ans+z*numx)%p;s[t][c][0]++;s[t][c][1]+=z;s[t][c][2]+=numz;s[t][c][3]+=z*numz;}}void output(){printf("%d\n",ans); fclose(stdin); fclose(stdout); }int main(){init(); solve(); output();return 0;4.推销员(salesman.cpp/c/pas)【问题描述】阿明是一名推销员,他奉命到螺丝街推销他们公司的产品。

螺丝街是一条死胡同,出口与入口是同一个,街道的一侧是围墙,另一侧是住户。

螺丝街一共有N 家住户,第i 家住户到入口的距离为S i 米。

由于同一栋房子里可以有多家住户,所以可能有多家住户与入口的距离相等。

阿明会从入口进入,依次向螺丝街的X 家住户推销产品,然后再原路走出去。

阿明每走1米就会积累1点疲劳值,向第i家住户推销产品会积累A i点疲劳值。

阿明是工作狂,他想知道,对于不同的X,在不走多余的路的前提下,他最多可以积累多少点疲劳值。

【输入格式】输入文件名为salesman.in。

第一行有一个正整数N,表示螺丝街住户的数量。

接下来的一行有N 个正整数,其中第i 个整数S i 表示第i 家住户到入口的距离。

数据保证S i <S<-<n S108。

接下来的一行有N 个正整数,其中第i 个整数A i 表示向第i 户住户推销产品会积累的疲劳值。

数据保证A i<103。

【输出格式】输出文件名为salesman.ou。

输出N 行,每行一个正整数,第i 行整数表示当X=i 时,阿明最多积累的疲劳值。

【数据说明】对于20%的数据,1< N< 20对于40%的数据,1< N< 100对于60%的数据,1< N< 1000对于100%的数据,1< N< 10000。

【思路】题目要求每一个X 的情况,显然不能每个X 专门推一遍,要充分利用已知的X 的情况,那么很可能会是DP 。

定义f[i] 为X=i 时的最大疲劳值。

关键是怎么建立状态转移方程呢?考试时观察了两组样例数据,直觉告诉我f[i+1]的决策应该会包含f[i]的决策(此处的决策指住户下标)。

事实上也确实如此。

证明:设f[i]的决策为也局,……,k i(k1< k2<……< k i), f[i+1]的决策将f[i]决策中的k s换成j并增加了一个决策k i+1, f[i+1]的决策k中最大的为maxk。

f[i]=2*s[k i]+ 艺a[k t](1<=t<=i)f[i+1]=2*s[maxk]+ 艺a[k t](1<=t<=s-1)+ 艺a[k t](s+1<=t<=i)+a[j]+a[k i+1]••• 2*s[maxk]+ 艺a[k t](1<=t<=s-1)+ 艺a[k t](s+1<=t<=i)+a[j]是X=i 时的一种决策的疲劳值(即决策为k1,k2, ....... k s-1,k s+1, .... k i,k j 时)二2*s[maxk]+ 艺a[k t](1<=t<=s-1)+ 艺a[k t](s+1<=t<=i)+a[j]<=f[i]二2*s[maxk]+ 艺a[k t](1<=t<=s-1)+ 艺a[k t](s+1<=t<=i)+a[j]+ a[k i+1] <=f[i]+ a[k M](即决策为k1,k2,……,k s,……,k i,k i+1时的疲劳值)若小于,说明保留k s更优;若等于,对于两个目前疲劳值相等的决策序列k,max{k} 越小越好(就是说目前走的路程越短越好),因为在max{k}左边的决策I只能增加a[l]的疲劳值,而对于max{k} 右边的决策r 则可以增加2*(s[r]-s[max{k}])+a[r] ,对于左边,max{k} 没有影响,而对于右边,max{k} 越小,后面的f[] 增加疲劳值的空间越大。

相关文档
最新文档