T1:fibonacci
题目:大M最近迷上了fibonacci数列,他定义了一种数列叫fibonacccccci数列: 1、这个数列包含至少2个元素; 2、f[0]和f[1]是任意选取的;3、 f[n+2]=f[n+1]+f[n](n>=0)现在给出一个数列a[1..n],你可以改变数列元素的顺序,使得a[1..m]满足fibonacccccci数列的条件,请求出最大的m。
数据范围:对于100%的数据,n≤500
思路:如果只有正数的话会简单很多,因为fibonacci是一个递增的数列,但是实际上题目里面会有负数,但其实也没有什么大不了,直接暴力找也是一样的,最多也就一个数找2n次。
代码:
const
maxn=500;
var
n,i,j,ans:longint;
a:array[1..maxn] of longint;
vis:array[1..maxn] of boolean;
function max(a,b:longint):longint;
begin
if a>b then exit(a) else exit(b);
end;
function match(l,r:longint):longint;
var
k,ans:longint;
flag:boolean;
begin
ans:=2;
fillchar(vis,sizeof(vis),true);
vis[l]:=false; vis[r]:=false;
while 1=1 do
begin
flag:=false;
for k:=1 to n do
if (vis[k]) and (a[l]+a[r]=a[k]) then
begin
inc(ans);
vis[k]:=false;
l:=r; r:=k;
flag:=true;
end;
if flag=false then break;
end;
exit(ans);
end;
begin
readln(n); ans:=0;
for i:=1 to n do read(a[i]);
for i:=1 to n-1 do
for j:=i+1 to n do
ans:=max(ans,match(i,j));
writeln(ans);
end.
题目:大M所在的怪兽大学共有n项课程,每项课程都有一个学分vi,各门课程的学分都有同一个上限maxv。在每年的毕业成绩结算中,一个怪兽的总成绩total=minx*cmin+cntmax*cmax,其中minx为这个怪兽n门课程中学分最低课程的分数,cntmax为这个怪兽n门课程中学分达到上限maxv的个数,cmin和cmax为给出的常数。现在学期已经过去大半,大M想要提高自己今年的总成绩。距离学期结束还有m天,每一天大M可以进修任意一门学分未满的课程并使该门课程的学分+1(你也可以什么课都不上)。请你帮帮大M,告诉他他最高可以获得的总成绩为多少。
数据规模:对于100%的数据,n<=100000,maxv<=10^5,cmax,cmin<=1000,m<=10^15,vi<=maxv;
思路:首先将学分按从大到小排序,再O(n)枚举要将学分修满的课程数,然后二分套二分找出当前状态学分最小值的最大值,更新答案。
代码:
const
maxn=100100;
var
maxv,cmax,cmin,m,ans,now,time,tmp:int64;
a,s,up,low:array[0..maxn] of int64;
n,i,x:longint;
function find(k,d:int64):longint;
var
l,r,mid:longint;
begin
l:=1; r:=k;
while l<=r do
begin
mid:=(l+r) div 2;
if low[mid]>d then r:=mid-1 else l:=mid+1;
end;
exit(r);
end;
procedure qsort(l,r:longint);
var
i,j,mid,tmp:longint;
begin
i:=l; j:=r; mid:=a[(l+r) div 2];
repeat
while a[i]>mid do inc(i);
while a[j]j;
if i=maxv then now:=n*cmax+maxv*cmin else now:=(n-i+1)*cmax+tmp*cmin;
if now>ans then ans:=now;
end;
writeln(ans);
end.
题目:众所周知,Alice和Bob是一对宿敌,每次博弈游戏中Alice和Bob总绞尽脑汁企图战胜对手,而且很不公平地,每次都是Alice先手。然而他们都看上了大M种的一棵巧克力树,为了取得更多的巧克力,他们决定联手合作。大M的巧克力树由n个节点组成,每个节点i上都有v[i]个巧克力,巧克力树上有n-1条树枝连接这整棵树(保证任意两点间存在一条路径)。Alice和Bob一开始都可以选择一个出发起点并获得该节点上的所有巧克力,当然,Alice先选。接下来,Alice和Bob会依次移动到自己节点相邻的节点上,并获得该节点上的所有巧克力。但是,任意节点都只能被经过一次,若Alice走过某个节点x,则Bob不能到达这个节点,当然Alice也不能走回x。问他们总共最多能获得多少巧克力?
数据规模:对于100%的数据,n<=100000,1<=v[i]<=10^9
思路:提供其中一种树形DP的解法:首先对于所有加入的边{x,y}加入其反向边{y,x}。用f[i]表示经过第i条边的最优答案,g[i]表示经过第i条边之后子树的最长链。假设第i条边为{y,x},我们用所有的以x为起点的边的(除去{x,y})的g值来更新f[i]。
代码:
const
maxn=100100;
type
edge=record
v,next:longint;
end;
var
e:array[0..maxn*2] of edge;
vis:array[0..maxn*2] of boolean;
f:array[0..2*maxn,0..1] of int64;
v:array[0..maxn] of int64;
head:array[0..maxn] of longint;
n,tot,i,x,y:longint;
ans:int64;
function max(a,b:int64):int64;
begin
if a>b then exit(a) else exit(b);
end;
procedure add(x,y:longint);
begin
inc(tot);
e[tot].v:=y; e[tot].next:=head[x]; head[x]:=tot;
inc(tot);
e[tot].v:=x; e[tot].next:=head[y]; head[y]:=tot;
end;
procedure dfs(x:longint);
var
tmp,go:longint;
max1,max2:int64;
begin
if vis[x] then exit;
vis[x]:=true;
go:=e[x].v; tmp:=head[go]; max1:=0; max2:=0; f[x,0]:=0;
while tmp<>-1 do
begin
if tmp<>x xor 1 then
begin
dfs(tmp);
f[x,0]:=max(f[x,0],f[tmp,0]);
if f[tmp,1]>max1 then
begin
max2:=max1; max1:=f[tmp,1];
end
else if f[tmp,1]>max2 then max2:=f[tmp,1];
end;
tmp:=e[tmp].next;
end;
f[x,0]:=max(f[x,0],max1+max2+v[go]);
f[x,1]:=max1+v[go];
end;
begin
readln(n);
for i:=1 to n do read(v[i]);
fillchar(head,sizeof(head),255); tot:=-1;
for i:=1 to n-1 do
begin
readln(x,y);
add(x,y);
end;
ans:=0;
for i:=0 to n-2 do
begin
dfs(2*i);
dfs(2*i+1);
ans:=max(ans,f[2*i,0]+f[2*i+1,0]);
end;
writeln(ans);
end.