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;
}
#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;
}
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 秒守望者能走的最远距离(跑和使用魔法的最优解)。
(感谢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.
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.
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 号的情况数即可。
(感谢愚一管晏如同学提供)
可以从每一步及每一步的情况数入手,例如: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;
}
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.
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;
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;
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.
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;
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,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.
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.
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.
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;
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;
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);
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;
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号拦截系统来拦,是否总代价会减少
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;
if dd[i,2]>max then max:=dd[i,2];
end;
writeln(min);
end.
end.
NOIP2010普及组复赛4.三国游戏sanguo
(感谢1402周俊豪同学提供)
(感谢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;
}
(感谢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分
(感谢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;
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;
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;
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;
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.
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.
浙公网安备 33010602011771号