i信息学奥赛

加入QQ群:1025629106,或关注微信公众号:i信息学奥赛,获取更多学习资源。

导航

解题报告

Posted on 2016-12-10 09:21  shnoip  阅读(434)  评论(0)    收藏  举报
NOIP2004提高组复赛3.合唱队形chorus
(感谢1604陈韬宇同学提供)
//双向最长上升子序列
#include<cstdio>
using namespace std;
int n,t[100],fl[100],fr[100],ans;  //fl为从左往右到当前项的最长上升子序列长度,fr为从右往左到当前项的最长上升子序列长度
int main()
{
    scanf("%d",&n);
    for (int i=0;i<n;i++) scanf("%d",&t[i]);
    fl[0]=1;
    for (int j=1;j<n;j++) {
      for (int i=0;i<=j-1;i++)
        if (t[i]<t[j] && fl[i]>fl[j]) fl[j]=fl[i];
      fl[j]++;
    }  //从左往右推

    fr[n-1]=1;
    for (int j=n-2;j>=0;j--) {
      for (int i=n-1;i>=j+1;i--)
        if (t[i]<t[j] && fr[i]>fr[j]) fr[j]=fr[i];
      fr[j]++;
    }  //从右往左推

    for (int i=0;i<n;i++)
      if (fl[i]+fr[i]-1>ans) ans=fl[i]+fr[i]-1;

    printf("%d",n-ans);
  return 0;
}
 
NOIP2006普及组复赛3.Jam的计数法count
(感谢1604陈韬宇同学提供)
#include<bits/stdc++.h>
using namespace std;
short s,t,w,a[25],bz;
string st;
int main()
{
  cin>>s>>t>>w;
  cin>>st;
  for (short i=0;i<w;i++) a[i]=st[i]-96;  //将字符串转换为数字
  for (short i=0;i<5;i++) {  //循环5次,输出后续的5个数字
    bz=w-1;  //标志位,因为a和st都是从0位开始,所以倒过来第1个要处理的是w-1位
    while (a[bz]==t-(w-1)+bz) bz--;  //从最后一位开始找,直到找出第一个可操作的字符
    a[bz]++;  //将这一位数加1
    for (short j=bz+1;j<w;j++)  //将其后的每一位都设定为最值
      a[j]=a[bz]+j-bz;
    for (short j=0;j<w;j++)  //将数字数组转换为字符形式输出
      cout<<char(a[j]+96);
    cout<<endl;
  }
  return 0;
}
 
 
NOIP2007普及组复赛3.守望者的逃离escape
(感谢1402周俊豪同学提供)
jl[t]表示在 t 秒守望者只用魔法能移动的距离,mf[t]表示在 t 秒守望者所拥有的魔法值,mjl[t]表示在 t 秒守望者能走的最远距离(跑和使用魔法的最优解)。
解法一
var
  m:integer;
  s,t,i:longint;
  mf:array[0..300000] of integer;
  jl,mjl:array[0..300000] of longint;
begin
  readln(m,s,t);
  mf[0]:=m;
  for i:=1 to t do begin
    if mf[i-1]>9 then begin  //魔法够就闪烁
      jl[i]:=jl[i-1]+60;
      mf[i]:=mf[i-1]-10;
    end
    else begin  //魔法不够就恢复
      jl[i]:=jl[i-1];
      mf[i]:=mf[i-1]+4;
    end;
    if mjl[i-1]+17>jl[i] then mjl[i]:=mjl[i-1]+17 
                         else mjl[i]:=jl[i];  //找出跑和使用魔法的最优解
    if mjl[i]>=s then begin  //顺利逃出
      writeln('Yes');
      writeln(i);
      halt;
    end;
  end;
  writeln('No');  //无法逃离
  writeln(mjl[i]);
end.
解法二
var
  m:integer;
  s,t,i,mjl:longint;
  jl:array[0..300000] of longint;
begin
  readln(m,s,t);
  for i:=1 to t do
    if m>9 then begin  //魔法够就闪烁
      jl[i]:=jl[i-1]+60;
      m:=m-10;
    end
    else begin  //魔法不够就恢复
      jl[i]:=jl[i-1];
      m:=m+4;
    end;
  for i:=0 to t-1 do
    if jl[i]+17>jl[i+1] then jl[i+1]:=jl[i]+17;
  while (jl[t-1]>s) and (t>0) do dec(t);
  if jl[t]>=s then begin writeln('Yes');writeln(t);end
              else begin writeln('No');writeln(jl[t]);end;
end.
 
NOIP2008普及组复赛3.传球游戏ball
(感谢愚一管晏如同学提供)
可以从每一步及每一步的情况数入手,例如:n=3,m=3,给同学们编号后小蛮为 1 号。m=1 时,球在 1 号手里显然不可能(0 种),在 2 号手里有 1 种情况,在 3 号手里有 1 种情况。m=2 来源于前一次的 m=1,1 号可以从 2 号或 3 号手里拿到球,共 2 种情况;3 号是 1 号和 2 号之前的情况数之和,1 种情况;2 号同 3号一样也是 1 种情况。
以此类推,每一次传球的结果都依赖于前一次传球的结果,且每次只需要记录下两组情况数:前一次和当前的一次。并在每一次统计结束后更新前一次,下次备用。最后要求的结果是球还在小蛮手里的情况数,直接取 1 号的情况数即可。
C++版
#include<cstdio>
using namespace std;
short n,m,i,j;
int s[31],e[31];
int main() {
  scanf("%hd %hd",&n,&m);
  s[1]=1;
  for (i=1;i<=m;i++) {
    for (j=1;j<=n;j++) {
      if (j==1) e[j]=s[n]+s[2];
      if (j==n) e[j]=s[n-1]+s[1];
      if (j>1 && j<n) e[j]=s[j-1]+s[j+1];
    }
    for (j=1;j<=n;j++) s[j]=e[j];
  }
  printf("%d\n",s[1]);
  return 0;
}
 
Pascal版
var
  i,k,n,m:byte;
  f:array[0..30,0..30] of longint;
begin
  readln(n,m);
  fillchar(f,sizeof(f),0);
  f[1,0]:=1;
  for k:=1 to m do begin
    f[1,k]:=f[2,k-1]+f[n,k-1];
    for i:=2 to n-1 do f[i,k]:=f[i-1,k-1]+f[i+1,k-1];
    f[n,k]:=f[n-1,k-1]+f[1,k-1];
  end;
  write(f[1,m]);
end.
 
NOIP2009普及组复赛1.多项式输出poly
(感谢1402王飞飏同学提供)
var
  i,n,x:shortint;
begin
  readln(n);
  for i:=n downto 0 do begin
    read(x);  //读入各项系数
    if x=0 then continue;  //系数为零跳过本次循环
    if (x>0) and (i<>n) then write('+');  //除开头外,其余各项系数若为正数输出+号
    if i=0 then write(x)  //最后一项直接输出系数
             else if (abs(x)<>1) then write(x)  //其余各项系数不为正负1的输出系数
                                             else if x=-1 then write('-');  //如果是-1输出-号(+1不用管)
    if i<>0 then if i=1 then write('x')  //接下来输出X和指数部分(三种情况:常数项、一次项和其余项)
                                 else write('x^',i);
  end;
  writeln;
end.
 
NOIP2009普及组复赛3.细胞分裂cell
type arr=array[1..30000,1..2] of longint;
var
  ans,g,i,k,n,m1,m2,total:longint;
  a:arr;
procedure factorization(k:longint;var a:arr;var link:longint);
var
  i:longint;
begin
  i:=1;link:=0;
  repeat
    inc(i);
    if k mod i=0 then begin
      inc(link);
      a[link,1]:=i;  //a的第1格存储因子是几,第2格存储这个因子有几个
      a[link,2]:=0;
      while k mod i=0 do begin
        inc(a[link,2]);
        k:=k div i;
      end;
    end;
  until k=1;  
end;
procedure check;
var i,z,max:longint;
begin
  max:=-1;
  read(k);
  for i:=1 to total do begin
    if k mod a[i,1]<>0 then exit;  //若k中没有这个质因子,则退出,此种细胞无解
    z:=0;
    while k mod a[i,1]=0 do begin  //统计k中这个质因子有多少个,存入z中
      inc(z);
      k:=k div a[i,1];
    end;
    if (a[i,2]+z-1) div z>max then max:=(a[i,2]+z-1) div z;  //(a[i,2]+z-1) div z中+z-1是为了凑整数;求出每个凑够每个因子所需的时间,并找出其中最大值
  end;
  if max<ans then ans:=max;  //用ans记录所有细胞分裂至能开始实验的最小值
end;
begin
  ans:=maxlongint;
  readln(n);
  readln(m1,m2);
  if m1=1 then begin
    writeln(0);
    halt;
  end;
  factorization(m1,a,total);  //对m1分解质因子,将每一个因子及其数量存储到a中,不同质因子总数存储到total中
  for i:=1 to total do a[i,2]:=a[i,2]*m2;
  for i:=1 to n do check;  //读入并检验每一种细胞
  if ans=maxlongint then writeln(-1)
                    else writeln(ans);
end.
 
NOIP2010普及组复赛1.数字统计two
解法一:
var
  l,r,i,j:integer;
  ans:longint;
begin
  read(l,r);
  ans:=0;
  for i:=l to r do begin
    j:=i;
    while j>0 do begin
      if j mod 10=2 then ans:=ans+1;
      j:=j div 10;
    end;
  end;
  write(ans);
end.
解法二:字符串
var
  l,r,i,j:integer;
  ans:longint;
  s:string;
begin
  read(l,r);
  ans:=0;
  for i:=l to r do begin
    str(i,s);
    for j:=1 to length(s) do if s[j]='2' then ans:=ans+1;
  end;
  write(ans);
end.
解法三:递归
var
  l,r,i:integer;
  ans:longint;
  a:array[0..10000] of byte;
begin
  read(l,r);
  ans:=0;
  for i:=0 to r do a[i]:=0;
  a[2]:=1;
  for i:=10 to r do a[i]:=a[i div 10]+a[i mod 10];
  for i:=l to r do ans:=ans+a[i];
  write(ans);
end.

NOIP2010普及组复赛2.接水问题water
(感谢1402周俊豪同学提供)
解法一:模拟(减法)
var
  a:array[1..10000] of byte;
  n,r,i:integer;
  m:byte;
  time:longint;
  f:boolean;
begin
  read(n,m);
  for i:=1 to n do read(a[i]);
  time:=0;
  r:=m;
  repeat
    time:=time+1;
    for i:=1 to m do if a[i]<>0 then a[i]:=a[i]-1  //扫描所有水龙头,若当前的人尚未接完,则继续接(减一)
                                else if r<n then begin  //若接完了,则下一个人开始接水
                                  r:=r+1;
                                  a[i]:=a[r]-1;
                                end;
    f:=true;
    for i:=1 to m do if a[i]<>0 then f:=false;  //是否所有人都接完了
  until f and (r=n);
  writeln(time);
end.
解法二:模拟(加法)
var
  a:array[1..10000] of longint;
  n,i:integer;
  m,k,j:byte;
begin
  read(n,m);
  for i:=1 to n do read(a[i]);
  for i:=m+1 to n do begin
    k:=1;
    for j:=2 to m do if a[j]<a[k] then k:=j;  //扫描所有水龙头,找出最小值,让下一个人接在最小值后面
    a[k]:=a[k]+a[i]
  end;
  k:=1;
  for i:=2 to m do if a[i]>a[k] then k:=i;  //找出所以水龙头队列中的最大值
  writeln(a[k]);
end.
 
NOIP2010普及组复赛3.导弹拦截missile
解法一:贪心(可通过7组测资)
var
  x1,y1,x2,y2,n,i,max1,max2,x,y,jl1,jl2:longint;
begin
  readln(x1,y1,x2,y2);
  readln(n);
  max1:=0;max2:=0;
  for i:=1 to n do begin
    readln(x,y);
    jl1:=sqr(x-x1)+sqr(y-y1);
    jl2:=sqr(x-x2)+sqr(y-y2);
    if (jl1>max1) and (jl2>max2) then  //导弹坐标在已有拦截范围之外
      if jl1<jl2 then max1:=jl1  //导弹离哪个拦截系统近,就由哪个拦截系统来拦
                 else max2:=jl2;
  end;
  writeln(max1+max2);
end.
解法二:贪心优化
var
  x1,y1,x2,y2,n,i,x,y,min,max:longint;
  dd:array [1..100000,1..2] of longint;
procedure qsort(l,r:longint);
var
  i,j,x,y:longint;
begin
  i:=l;j:=r;x:=dd[(l+r) div 2,1];
  repeat
    while dd[i,1]>x do inc(i);
    while x>dd[j,1] do dec(j);
    if i<=j then begin
      y:=dd[i,1]; dd[i,1]:=dd[j,1]; dd[j,1]:=y;
      y:=dd[i,2]; dd[i,2]:=dd[j,2]; dd[j,2]:=y;
      inc(i); dec(j);
    end;
  until i>j;
  if l<j then qsort(l,j);
  if i<r then qsort(i,r);
end;
begin
  readln(x1,y1,x2,y2);
  readln(n);
  for i:=1 to n do begin  //读入每个导弹坐标,存储其与二个拦截系统的距离
    readln(x,y);
    dd[i,1]:=sqr(x-x1)+sqr(y-y1);
    dd[i,2]:=sqr(x-x2)+sqr(y-y2);
  end;
  qsort(1,n);  //按每个导弹与1号拦截系统距离由大到小排序
  min:=dd[1,1];  //2套拦截系统的最小代价和
  max:=dd[1,2];  //2号拦截系统目前代价
  for i:=2 to n do begin  //从距1号拦截系统最远的导弹开始一个个的检测,如果该导弹改由2号拦截系统来拦,是否总代价会减少
    if dd[i,1]+max<min then min:=dd[i,1]+max;
    if dd[i,2]>max then max:=dd[i,2];
  end;
  writeln(min);
end.
 
NOIP2010普及组复赛4.三国游戏sanguo
(感谢1402周俊豪同学提供)
1、比胜负靠的是双方武将中默契值最大的那一对,所以除了默契值最大的那一对,其他的武将都可以忽略。
2、小涵是不会输的,因为小涵先手,计算机则按固定策略跟着小涵选。如果最终计算机的最大默契值比小涵的小,那么毫无疑问小涵就赢了;而如果计算机的武将搭配默契值比小涵的大,那么小涵完全可以换方法选,从计算机的方案的角度选,得到更优方案。
3、在一个武将和其他所有武将的搭配方案中,默契值最大的是拿不到的,因为小涵不能一下选两个武将,计算机又要和小涵抢。但是,在一个武将和其他所有武将的搭配方案中,默契值次大的那对,小涵可以稳拿。
 
var
  n,i,j:integer;
  mq:array[1..500,1..500] of longint;
  max1,max2,ans:longint;
begin
  readln(n);
  for i:=1 to n-1 do begin
    for j:=i+1 to n do begin
      read(mq[i,j]);
      mq[j,i]:=mq[i,j]  //复制到左下角,形成一个n*n的默契值二维表
    end;
    readln;
  end;
  for i:=1 to n do begin
    max1:=0;max2:=0;
    for j:=1 to n do
      if mq[i,j]>max1 then begin max2:=max1;max1:=mq[i,j];end
                      else if mq[i,j]>max2 then max2:=mq[i,j];  //找出每个武将的第二大默契值
    if max2>ans then ans:=max2;  //找出所有武将中第二大默契值的最大值
  end;
  writeln(1);
  writeln(ans);
end.
 
NOIP2010提高组复赛2.乌龟棋tortoise
(感谢1604陈韬宇同学提供)

#include<cstdio>
#include<algorithm>
using namespace std;
int n,m,t,a,b,c,d,q[351],f[41][41][41][41];  //f数组表示用到第i张1号卡,第j张2号卡,第k张3号卡,第l张4号卡时所能得到的最高分数
int main()
{
  scanf("%d%d",&n,&m);
  for (int i=0;i<n;i++) scanf("%d",&q[i]);
  for (int i=0;i<m;i++) {
    scanf("%d",&t);
    if (t==1) a++;
    if (t==2) b++;
    if (t==3) c++;
    if (t==4) d++;
  }  //统计每类卡的数量
  f[0][0][0][0]=q[0];  //初始化第一格
  for (int i=0;i<=a;i++)
  for (int j=0;j<=b;j++)
  for (int k=0;k<=c;k++)
  for (int l=0;l<=d;l++) {
    if (i) f[i][j][k][l]=max(f[i][j][k][l],f[i-1][j][k][l]+q[i+2*j+3*k+4*l]);
    if (j) f[i][j][k][l]=max(f[i][j][k][l],f[i][j-1][k][l]+q[i+2*j+3*k+4*l]);
    if (k) f[i][j][k][l]=max(f[i][j][k][l],f[i][j][k-1][l]+q[i+2*j+3*k+4*l]);
    if (l) f[i][j][k][l]=max(f[i][j][k][l],f[i][j][k][l-1]+q[i+2*j+3*k+4*l]);
  }  //为防止数组越界,进行条件判断,然后四维DP
  printf("%d",f[a][b][c][d]);
  return 0;
}

NOIP2011提高组复赛day1 1.铺地毯carpet
(感谢1402周俊豪同学提供)
var
  n,i:integer;
  a,b,g,k:array[1..10000] of longint;
  x,y:longint;
begin
  readln(n);
  for i:=1 to n do readln(a[i],b[i],g[i],k[i]);
  readln(x,y);
  for i:=n downto 1 do  //从后往前扫,找到第一个覆盖这个点的就输出,否则无解。
    if (x>=a[i]) and (x<=a[i]+g[i]) and (y>=b[i]) and (y<=b[i]+k[i]) then begin
      writeln(i);exit;
    end;
  writeln(-1);
end.
 
NOIP2012普及组复赛1.质因数分解prime
二个素数的积一定是合数,且只有4个因子(1,第1个素数,第2个素数,它们的积)
var
  n,i:longint;
begin
  readln(n);
  for i:=2 to 44721 do  //sqrt(2000000000)
    if n mod i=0 then
      begin writeln(n div i); break; end;
end.
 
NOIP2012普及组复赛2.寻宝treasure
直接模拟
var
  n,i,be,en,ru,my:integer;
  m,j,lt:shortint;
  cbl:array[1..10000,0..99,1..2] of longint;
  lts:array[1..10000] of byte;
begin
  readln(n,m);
  for i:=1 to n do begin  //读入藏宝楼各层各房间信息
    lt:=0;
    for j:=0 to m-1 do begin
      readln(cbl[i,j,1],cbl[i,j,2]);
      lt:=lt+cbl[i,j,1];
    end;
    lts[i]:=lt;  //存储每一层有楼梯的房间数
  end;
  readln(be);  //进入藏宝楼底层的房间号
  my:=0;  //宝箱密钥
  for i:=1 to n do begin
    en:=be;
    my:=(my+cbl[i,be,2]) mod 20123;
    ru:=cbl[i,be,2] mod lts[i];  //对每一层有楼梯的房间数取模,降低时间复杂度
    if ru=0 then ru:=lts[i];
    repeat  //开始模拟
      if cbl[i,en,1]=1 then ru:=ru-1;
      if ru=0 then break;
      en:=en+1;
      if en=m then en:=0;
    until false;
    be:=en;
  end;
  writeln(my);
end.
 
NOIP2014普及组复赛1.珠心算测验count
(感谢新世纪庞可同学提供)
var
  n,i,j,ans:byte;
  s:array[1..100] of integer;
  h:array[1..20000] of boolean;
begin
  readln(n);
  for i:=1 to n do read(s[i]);  //读入n个正整数
  for i:=1 to n-1 do  //在h数组中标记任意两个正慗数的和的值
    for j:=i+1 to n do h[s[i]+s[j]]:=true;
  for i:=1 to n do  //扫描这个n个正整数,检查是否有正整数与h数组中标记的值相等
    if h[s[i]] then ans:=ans+1;
  writeln(ans);
end.
 
NOIP2014普及组复赛2.比例简化ratio
(感谢新世纪庞可同学提供)
var
  a,b:longint;
  l,i,j,c,d:byte;
  bz,min,t:real;
function gcd(a,b:byte):byte;
var
  c:byte;
begin
  while b>0 do begin
    c:=a mod b;
    a:=b;
    b:=c;
  end;
  gcd:=a;
end;
begin
  readln(a,b,l);
  bz:=a/b;
  min:=1000000;
  for i:=1 to l do  //在1到L范围内穷举分子和分母
    for j:=1 to l do
      if gcd(i,j)=1 then begin  //如果互质
      t:=i/j-bz;  //A'/B'-A/B的值
      if (t>=0) and (t<min) then begin c:=i;d:=j;min:=t;end;  //找最小值,并用c、d记录分子和分母
    end;
  writeln(c,' ',d);
end.
 
NOIP2014普及组复赛3.螺旋矩阵matrix
(感谢格致初杭业晟同学提供)
var
  n,i,j,ans:longint;
begin
  readln(n,i,j);
  ans:=0;
  while not ((i=1) or (i=n) or (j=1) or (j=n)) do begin  //只要i、j还不是矩形的四个角,就一圈圈地剥掉最外层
    ans:=ans+4*n-4;  //计算矩形左上角左边一个格子的值
    n:=n-2;
    i:=i-1;
    j:=j-1;
  end;
  if i=1 then writeln(ans+j)  //如果在最上面一层
           else if i=n then writeln(ans+3*n-j-1)  //如果在最下面一层
                            else if j=1 then writeln(ans+4*n-i-2)  //如果在第一列
                                             else writeln(ans+n+i-1);  //如果在最后一列
end.
 
NOIP2014普及组复赛4.子矩阵submatrix
(感谢1402周俊豪同学提供)
暴力搜索,可以拿到50分
type
  da=array[1..17] of byte;
var
  n,m,r,c,i,j:byte;
  min:longint;
  s:array[1..16,1..16] of integer;
  sr,sc:da;
function count(sr,sc:da):longint;  //计算当前穷举到的子矩阵的分值
var
  i,j:byte;
begin
  sr[r+1]:=sr[r];
  sc[c+1]:=sc[c];
  count:=0;
  for i:=1 to r do
    for j:=1 to c do
      count:=count+abs(s[sr[i],sc[j]]-s[sr[i+1],sc[j]])+abs(s[sr[i],sc[j]]-s[sr[i],sc[j+1]]);
end;
procedure column(cs,p:byte);  //穷举列,用变量p保证序列递增
var
  i:byte;
  t:longint;
begin
  if cs=c then begin
    t:=count(sr,sc);  //用sr,sc两个数组存储当前搜索到的子矩阵在原矩阵中的行列编号
    if t<min then min:=t;
    exit;
  end;
  for i:=p+1 to m do begin
    sc[cs+1]:=i;
    column(cs+1,i);
  end;
end;
procedure row(rs,p:byte);  //穷举行
var
  i:byte;
begin
  if rs=r then begin column(0,0);exit;end;
  for i:=p+1 to n do begin
    sr[rs+1]:=i;
    row(rs+1,i);
  end;
end;
begin
  readln(n,m,r,c);
  for i:=1 to n do begin
    for j:=1 to m do read(s[i,j]);
    readln;
  end;
  min:=2147483647;
  row(0,0);
  writeln(min);
end.
 
NOIP2014提高组复赛day1 1.生活大爆炸版石头剪刀布rps
var
  n,na,nb,fa,fb,i,ta,tb:byte;
  a,b:array[1..200] of byte;
begin
  readln(n,na,nb);
  for i:=1 to na do read(a[i]);
  readln;
  for i:=1 to nb do read(b[i]);
  readln;
  for i:=1 to n do begin
    ta:=i mod na;
    if ta=0 then ta:=na;
    tb:=i mod nb;
    if tb=0 then tb:=nb;
    case a[ta] of  //计算小A得分
      0:  if (b[tb]=2) or (b[tb]=3) then inc(fa);
      1:  if (b[tb]=0) or (b[tb]=3) then inc(fa);
      2:  if (b[tb]=1) or (b[tb]=4) then inc(fa);
      3:  if (b[tb]=2) or (b[tb]=4) then inc(fa);
      4:  if (b[tb]=0) or (b[tb]=1) then inc(fa);
    end;
    case b[tb] of  //计算小B得分
      0:  if (a[ta]=2) or (a[ta]=3) then inc(fb);
      1:  if (a[ta]=0) or (a[ta]=3) then inc(fb);
      2:  if (a[ta]=1) or (a[ta]=4) then inc(fb);
      3:  if (a[ta]=2) or (a[ta]=4) then inc(fb);
      4:  if (a[ta]=0) or (a[ta]=1) then inc(fb);
    end;
  end;
  writeln(fa,' ',fb);
end.

 

NOIP2015普及组复赛1.金币coin
有一个规律:1枚金币发1天,2枚金币连发2天,3枚金币连发3天……金币枚数即连发天数
var
  d,t:byte;
  n,i:integer;
  ans:longint;
begin
  readln(n);
  d:=1;t:=1;  //t为某天发放的金币数,d为某数量金币发放的天数
  for i:=1 to n do begin
    ans:=ans+t;
    d:=d-1;
    if d=0 then begin t:=t+1;d:=t;end;
  end;
  writeln(ans);
end.

 

NOIP2015普及组复赛2.扫雷游戏mine
var
  n,m,i,j,ans:byte;
  s:array[0..101,0..101] of char;  //为方便统计非地雷格周围地雷个数,行列范围从1-100扩大到0-101
begin
  readln(n,m);
  for i:=1 to n do begin  //读入雷区
    for j:=1 to m do read(s[i,j]);
    readln;
  end;
  for i:=1 to n do begin  //扫描雷区每一格
    for j:=1 to m do
      if s[i,j]='*' then write('*')  //若是地雷输出星号,否则统计周围地雷个数,输出其值
                    else begin
       ans:=0;
       if s[i-1,j-1]='*' then inc(ans);
       if s[i-1,j]='*' then inc(ans);
       if s[i-1,j+1]='*' then inc(ans);
       if s[i,j-1]='*' then inc(ans);
       if s[i,j+1]='*' then inc(ans);
       if s[i+1,j-1]='*' then inc(ans);
       if s[i+1,j]='*' then inc(ans);
       if s[i+1,j+1]='*' then inc(ans);
       write(ans);
      end;
    writeln;
  end;
end.

NOIP2015普及组复赛3.求和sum
暴力法(当n大于3000会超时,可得40分)
var
  n,m,i,j,ans:longint;
  co,nu:array[1..100000] of longint;
begin
  readln(n,m);
  for i:=1 to n do read(nu[i]);readln;
  for i:=1 to n do read(co[i]);readln;
  for i:=1 to n-2 do
    for j:=i+2 to n do
      if ((i+j) mod 2=0) and (co[i]=co[j]) then ans:=(ans+(i+j)*(nu[i]+nu[j])) mod 10007;
  writeln(ans);
end.

NOIP2015普及组复赛4.推销员salesman
(感谢1402周俊豪同学提供)
暴力法(当n大于1000会超时,可得60分)
每一次的最优解必然包含了上一次的最优解,也就是说只要知道这一轮的最大疲劳值就行了,即这一轮能多消耗的疲劳值的最大值。可以分成两种情况:一、距离小于已经到达的最远距离;二、距离大于已经到达的最远距离。
var
  n,i,j,dq,p,maxp,t,ans:longint;
  s:array[1..100000] of longint;
  a:array[1..100000] of integer;
begin
  readln(n);
  for i:=1 to n do read(s[i]);readln;
  for i:=1 to n do read(a[i]);readln;

  for i:=1 to n do begin
    maxp:=0;
    for j:=1 to n do begin
      if s[j]>dq then p:=2*s[j]+a[j]-2*dq
                 else p:=a[j];
      if p>maxp then begin maxp:=p;t:=j;end;
    end;
    if s[t]>dq then dq:=s[t];
    s[t]:=0;a[t]:=0;
    ans:=ans+maxp;
    writeln(ans);
  end;
end.

NOIP2015提高组复赛day1 1.神奇的幻方magic
 
var
  n,i,j:byte;
  s:integer;
  m:array[1..39,1..39] of integer;
begin
  readln(n);
  s:=1;  //准备存入第一个数,i、j为行、列坐标
  i:=1;j:=(n+1) div 2;
  m[i,j]:=s;
  while s<n*n do begin
    s:=s+1;
    if (i=1) and (j<>n) then begin i:=n;j:=j+1;m[i,j]:=s;continue;end;  //前一个数在第一行但不在最后一列
    if (i<>1) and (j=n) then begin i:=i-1;j:=1;m[i,j]:=s;continue;end;  //前一个数不在第一行但在最后一列
    if (i=1) and (j=n) then begin i:=i+1;m[i,j]:=s;continue;end;  //前一个数在第一行最后一列
    if m[i-1,j+1]=0 then begin i:=i-1;j:=j+1;end
                    else i:=i+1;
    m[i,j]:=s;
  end;
  for i:=1 to n do  //输出,注意每行最后是数字,不能是空格
    for j:=1 to n do
      if j<n then write(m[i,j],' ')
             else writeln(m[i,j]);
end.
仔细研究题目,你会发现新数只会填在老数的右上方(滚动)或正下方,可简化如下:
var
  n,i,j:byte;
  s:integer;
  m:array[0..38,0..38] of integer;  //为了滚动(mod)方便,将数组定义为0至38
begin
  readln(n);
  s:=1;
  i:=0;j:=n div 2;
  m[i,j]:=s;
  while s<n*n do begin
    s:=s+1;
    if m[(i-1+n) mod n,(j+1) mod n]=0 then begin
      i:=(i-1+n) mod n;
      j:=(j+1) mod n;
    end else i:=(i+1) mod n;
    m[i,j]:=s;
  end;
  for i:=0 to n-1 do
    for j:=0 to n-1 do
      if j<n-1 then write(m[i,j],' ')
               else writeln(m[i,j]);
end.