Day1

1.xth的阶梯 (stair.pas/c/cpp)

描述

Xth家有一个很长很长的楼梯,有n级,现在你想要走完这个阶梯。

开始时你在0级,你可以一步走一级或两级。最后一步必须恰好落到第n级上

请你求出有多少种行走方案可以走完这个阶梯。为了降低编程复杂度,只需输出最后的结果mod 123456的值即可

输入格式(stair.in)

第一行:

一个整数n

输出格式(stair.out)

一行:最后的结果

样例输入

2

样例输出

2

数据范围

50%的数据:n<=2^20;

100%的数据:n<=2^64-1;

 

//斐波那契数列

program __stair;
type
  arr=array[1..2,1..2] of int64;
var
  a,b:arr;
  n,ans:int64;
procedure multity(var a,b:arr);
  var
    c:arr;
    i,j,k:longint;
  begin
    fillchar(c,sizeof(c),0);
    for i:=1 to 2 do
      for j:=1 to 2 do
        for k:=1 to 2 do
          c[i][j]:=(c[i][j]+a[i][k]*b[k][j]) mod 123456;
    a:=c;
  end;
procedure power(i:int64);
  var
    t:arr;
  begin
    t:=a;
    b:=a;
    dec(i);
    while (i>0) do
      begin
        if (i and 1=1) then multity(b,t);
        i:=i shr 1;
        multity(t,t);
      end;
  end;
begin
  assign(input,'stair.in');
  reset(input);
  assign(output,'stair.out');
  rewrite(output);
  readln(n);
  close(input);
  if (n<2) then
    begin
      writeln(1);
      close(output);
      halt;
    end;
  dec(n);
  a[1][1]:=1;
  a[1][2]:=1;
  a[2][1]:=1;
  a[2][2]:=0;
  power(n);
  ans:=(b[1][1]+b[2][1]) mod 123456;
  writeln(ans);
  close(output);
end.

 

2.pizza

描述:

Dsqwwe从小到大都没有吃过披萨,今天,他终于忍不住了,于是他叫了一份必胜客的外卖,由于不是dsqwwe一个人叫外卖,送外卖的小哥要到每个叫外卖的顾客家中然后最后回到必胜客…..这里有n-1个顾客叫外卖,必胜客在1号路口,叫外卖的顾客家分别在2,3,4…..n号路口,每两个路口都有一条通路,小哥想保证送外卖的时间最少,问最少时间为多少(一个路口可以多次经过的)

输入:

第一行:n(2<=n<=15)

接下来n行每行n个数,第i行第j列代表从i到j的时间,当然这个矩阵是沿对角线对称的,且i行i列为0,除此外都不为0

输出:

最少时间

样例输入:

4
0 1 10 10
1 0 1 2
10 1 0 10
10 2 10 0

样例输出:

8

 

//二维记录状态SPFA

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int n;
int a[16][16];
int d[32769][16];
struct node{
	int x,id;
}f[1100000];
bool v[32769][16];
void SPFA(){
	memset(d,63,sizeof(d));
	d[1][1]=0;
	f[1].x=1;
	f[1].id=1;
	int head=0,tail=1;
	while (head<tail){
		int x=f[++head].x;
		int id=f[head].id;
		v[id][x]=false;
		for (int i=1;i<=n;i++)if (i!=x){
			if (d[id | (1 << (i -1))][i]>d[id][x]+a[x][i]){
				d[id | (1 << (i-1))][i]=d[id][x]+a[x][i];
				if (!v[id | (1 << (i-1))][i]){
					v[id | (1 << (i-1))][i]=true;
					f[++tail].x=i;
					f[tail].id=id | (1 << (i-1));
				}
			}
		}
	}
}			
int main(){
	freopen("pizza.in","r",stdin);
	freopen("pizza.out","w",stdout);
	cin>>n;
	for (int i=1;i<=n;i++){
		for (int j=1;j<=n;j++){
			cin>>a[i][j];
		}
	}
	SPFA();
	int ans=d[(1 << n)-1][1];
	printf("%d\n",ans);
	return 0;
}

//状态压缩DP+floyd最短路

var
  a:array[1..15,1..15] of longint;
  f:array[0..65535,1..15] of longint;
  n,i,j,k,ans,lim:longint;
function min(a,b:longint):longint;
  begin
    if (a<b) then exit(a) else exit(b);
  end;
begin
  assign(input,'pizza.in');
  reset(input);
  assign(output,'pizza.out');
  rewrite(output);
  readln(n);
  for i:=1 to n do
    for j:=1 to n do
      begin
        read(a[i][j]);
      end;
  for k:=1 to n do
    for i:=1 to n do
      if (i<>k) then
      for j:=1 to n do
      if (j<>k) and (i<>j) then
        if (a[i][k]+a[k][j]<a[i][j]) then a[i][j]:=a[i][k]+a[k][j];
  fillchar(f,sizeof(f),63);
  lim:=1 shl n-1;
  f[1][1]:=0;
  for i:=1 to lim do
    for j:=1 to n do
      if ((i and (1 shl (j-1)))=(1 shl (j-1))) then
         begin
            for k:=1 to n do
               if ((i and (1 shl (k-1)))=0) then
                 begin
                    f[i or (1 shl (k-1))][k]:=min(f[i or (1 shl (k-1))][k],f[i][j]+a[k][j]);
                 end;
        end;
  ans:=maxlongint;
  for i:=1 to n-1 do
     if (ans>f[lim][i]+a[i][1]) then ans:=f[lim][i]+a[i][1];
  writeln(ans);
  close(input);
  close(output);
end.

3.xth的苹果树(apple.pas/c/cpp)

描述

xth种了一棵苹果树,这棵树由n个节点构成,中间有树枝连接,苹果都会长在节点上,并且不会有两个苹果长在同一个节点上。Xth想知道某个子树上有多少个苹果,你能帮帮他吗?(1号节点为跟)

输入格式(apple.in)

第一行:一个整数n,表示苹果树有n个节点。

以下n-1行:每行两个整数u、v,表示u、v两节点间有树枝相连。

第n+1行:一个整数m,表示有m个询问或操作。

以下m行:一个字符(’C’或’Q’)和一个整数x。‘C’表示将x节点处的苹果有无情况取反。‘Q’表示询问以x为根的子树中苹果的个数。

注:苹果树开始时是长满苹果的。

输出格式(apple.out)

对于每一个询问输出一行,一个整数,表示苹果数。

输入样例

3

1 2

1 3

3

Q 1

C 2

Q 1

输出样例

3

2

数据规模

N<=100000,M<=100000

 

//树状数组

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int n,m;
struct edge{
	int x,next;
}e[200000],e2[200000];
int tot,tot2;
int first[110000],first2[110000];
int a[110000];
int fa[110000];
int l[110000],r[110000];
int v[110000];
void add2(int a,int b){
	e2[++tot2].x=b;
	e2[tot2].next=first2[a];
	first2[a]=tot2;
}
void add(int a,int b){
	e[++tot].x=b;
	e[tot].next=first[a];
	first[a]=tot;
}
bool vis[110000];
void build(int x){
	vis[x]=true;
	for (int t=first2[x];t;t=e2[t].next){
		if (!vis[e2[t].x]){
			fa[e2[t].x]=x;
			add(x,e2[t].x);
			build(e2[t].x);
		}
	}
}
int cnt;
void makeque(int x){
	r[x]=cnt;
	l[x]=cnt;
	--cnt;
	for (int t=first[x];t;t=e[t].next){
		makeque(e[t].x);
		l[x]=min(l[x],l[e[t].x]);
	}
}
inline int lowbit(int x){return x & (x ^ (x-1));}
void Plus(int x,int k){
	while (x<=n){
		a[x]+=k;
		x+=lowbit(x);
	}
}
int sum(int x){
	int tot=0;
	while (x>0){
		tot+=a[x];
		x-=lowbit(x);
	}
	return tot;
}
int main(){
	freopen("apple.in","r",stdin);
	freopen("apple.out","w",stdout);
	scanf("%d",&n);
	for (int i=1;i<n;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		add2(x,y);
		add2(y,x);
	}
	build(1);
	cnt=n;
	makeque(1);
	for (int i=1;i<=n;i++){
		Plus(i,1);
	}
	scanf("%d\n",&m);
	for (int i=1;i<=m;i++){
		char ch;
		int x;
		scanf("%c %d\n",&ch,&x);
		if (ch=='C'){
			if (!v[r[x]]){
                       Plus(r[x],-1);
                       v[r[x]]=1;
            }else{
                  Plus(r[x],1);
                  v[r[x]]=0;
            }
		}else{
			int ans=sum(r[x])-sum(l[x]-1);
			printf("%d\n",ans);
		}
	}
	return 0;
}
//模拟(低效率刚刚过0.98s)
program __apple;
type
  edge=record
    x,next:longint;
  end;
var
  e,e2:array[0..200000] of edge;
  first,first2:array[0..110000] of longint;
  tot,tot2:longint;
  fa:array[0..110000] of longint;
  num:array[0..110000] of longint;
  a:array[0..110000] of longint;
  v:array[0..110000] of boolean;
  i,n,m,x,y:longint;
  ch:char;
procedure add(a,b:longint);
  begin
    inc(tot);
    e[tot].x:=b;
    e[tot].next:=first[a];
    first[a]:=tot;
  end;
procedure add2(a,b:longint);
  begin
    inc(tot2);
    e2[tot2].x:=b;
    e2[tot2].next:=first2[a];
    first2[a]:=tot2;
  end;
procedure build(x:longint);
  var
    t:longint;
  begin
    v[x]:=true;
	num[x]:=1;
    t:=first2[x];
    while (t<>0) do
      begin
        if (not v[e2[t].x]) then
          begin
            add(x,e2[t].x);
            fa[e2[t].x]:=x;
            build(e2[t].x);
			inc(num[x],num[e2[t].x]);
          end;
        t:=e2[t].next;
      end;
  end;
{
procedure makenum(x:longint);
  var
    t:longint;
  begin
    num[x]:=1;
    t:=first[x];
    while (t<>0) do
      begin
        makenum(e[t].x);
        inc(num[x],num[e[t].x]);
        t:=e[t].next;
      end;
  end;
}
procedure change(x,y:longint);
  var
    i:longint;
  begin
    inc(num[x],y);
    i:=fa[x];
    while (i<>0) do
      begin
        inc(num[i],y);
        i:=fa[i];
      end;
  end;
begin
  assign(input,'apple.in');
  reset(input);
  assign(output,'apple.out');
  rewrite(output);
  readln(n);
  for i:=1 to n-1 do
    begin
      readln(x,y);
      add2(x,y);
      add2(y,x);
    end;
  build(1);
  //makenum(1);
  readln(m);
  for i:=1 to m do
    begin
      readln(ch,x);
      if (ch='Q') then
        writeln(num[x])
      else
        begin
          if (a[x]=0) then
            begin
              change(x,-1);
              a[x]:=1;
            end
          else
            begin
              change(x,1);
              a[x]:=0;
            end;
        end;
    end;
  close(input);
  close(output);
end.

 

Day2

1.xth的舞会(party.pas/c/cpp)

描述

xth准备开一个舞会。

  他准备邀请n个已经确定的人,可是问题来了:

  这n个人每一个人都有一个小花名册,名册里面写着他所愿意交流的人的名字。比如说在A的人名单里写了B,那么表示A愿意与B交流;但是B的名单里不见的有A,也就是说B不见的想与A交流。但是如果A愿意与B交流,B愿意与C交流,那么A一定愿意与C交流。也就是说交流有传递性。

Xth觉得需要将这n个人分为m组,要求每一组的任何一人都愿意与组内其他人交流。并求出一种方案以确定m的最小值是多少。

  注意:自己的名单里面不会有自己的名字。

输入格式(party.in)

第一行一个数n。接下来n行,每i+1行表示编号为i的人的小花名册名单,名单以0结束。1<=n<=200。

输出格式(party.out)

一个数,m。

输入样例

18

0

18 0

0

0

11 0

0

0

0

0

0

5 0

0

0

0

0

0

0

2 0

输出样例

16

数据规模

1<=n<=200

//tarjan

program __party;
type
  Edge=record
    x,next:longint;
  end;
var
  e:array[0..100000] of Edge;
  first:array[0..210] of longint;
  n,i,cnt,times,top,x,tot:longint;
  stack,low,dfn:array[0..210] of longint;
  instack:array[0..210] of boolean;
function min(a,b:longint):longint;
  begin
    if (a<b) then exit(a) else exit(b);
  end;
procedure add(a,b:longint);
  begin
    inc(tot);
    e[tot].x:=b;
    e[tot].next:=first[a];
    first[a]:=tot;
  end;
procedure tarjan(u:longint);
  var
    t,i,v:longint;
  begin
    inc(times);
    dfn[u]:=times;
    low[u]:=times;
    instack[u]:=true;
    inc(top);
    stack[top]:=u;
    t:=first[u];
    while (t<>0) do
      begin
        v:=e[t].x;
        if (dfn[v]=0) then
          begin
            tarjan(v);
            low[u]:=min(low[u],low[v]);
          end
        else
          if (instack[v]) then low[u]:=min(low[u],dfn[v]);
        t:=e[t].next;
      end;
    if (low[u]=dfn[u]) then
      begin
        inc(cnt);
        repeat
          i:=stack[top];
          instack[i]:=false;
          dec(top);
        until i=u;
      end;
  end;
begin
  assign(input,'party.in');
  reset(input);
  assign(output,'party.out');
  rewrite(output);
  readln(n);
  for i:=1 to n do
    begin
      read(x);
      while (x<>0) do
        begin
          add(i,x);
          read(x);
        end;
      readln;
    end;
  for i:=1 to n do
    if (dfn[i]=0) then tarjan(i);
  writeln(cnt);
  close(input);
  close(output);
end.

 

2.climbing(climbing.pas/c/cpp)

描述:

Dsqwwe很喜欢旅游,这次他和他的朋友去爬山,途中遇到一处悬崖,dsqwwe决定挑战自己。这处悬崖可以描述为一个n*m的矩阵,矩阵中s代表落脚点,t代表终点,数字带表一只脚落到上面所需时间,X代表此处无法落脚。攀登时,先把左脚或右脚放在任意一处s处,然后另一只脚开始攀登,攀登时,当然是左脚一步,右脚一步。

若一只脚在(x1,y1),另一只脚落地的范围要保证 |x1-x2|+|y1-y2|<=3,若左脚固定,迈右脚只能往右边迈。右脚固定迈左脚只能向左边迈,如图:

clip_image002

当任意一只脚落在t处,则攀登结束,为攀登所需的最少时间为多少

输入(climbing.in):

注意多组数据

对于每组数据,第一行为两个整数,n,m(0<=n,m<=100)

然后就是一个n*m的矩阵,描述悬崖

输出(climbing.out):

若无法完成攀登,输出-1

若可以完成攀登,输出最小时间

样例输入:

6 6
4 4 X X T T
4 7 8 2 X 7
3 X X X 1 8
1 2 X X X 6
1 1 2 4 4 7
S S 2 3 X X
2 10
T 1
1 X
1 X
1 X
1 1
1 X
1 X
1 1
1 X
S S
2 10
T X
1 X
1 X
1 X
1 1
1 X
1 X
1 1
1 X
S S
10 10
T T T T T T T T T T
X 2 X X X X X 3 4 X
9 8 9 X X X 2 9 X 9
7 7 X 7 3 X X 8 9 X
8 9 9 9 6 3 X 5 X 5
8 9 9 9 6 X X 5 X 5
8 6 5 4 6 8 X 5 X 5
8 9 3 9 6 8 X 5 X 5
8 3 9 9 6 X X X 5 X
S S S S S S S S S S
10 7
2 3 2 3 2 3 2 3 T T
1 2 3 2 3 2 3 2 3 2
3 2 3 2 3 2 3 2 3 4
3 2 3 2 3 2 3 2 3 5
3 2 3 1 3 2 3 2 3 5
2 2 3 2 4 2 3 2 3 5
S S 2 3 2 1 2 3 2 3

样例输出:

12
5
-1
22
12

样例解释

第一组(l代表左脚,r代表右脚):

4 4 X X T T

4 7 8 2 X 7

3 X X X 1 8

1 R X X X 6

1 1 2 4 4 7

L S 2 3 X X

4 4 X X T T

L 7 8 2 X 7

3 X X X 1 8

1 R X X X 6

1 1 2 4 4 7

S S 2 3 X X

4 4 X X T T

L 7 8 R X 7

3 X X X 1 8

1 2 X X X 6

1 1 2 4 4 7

S S 2 3 X X

4 L X X T T

4 7 8 R X 7

3 X X X 1 8

1 2 X X X 6

1 1 2 4 4 7

S S 2 3 X X

4 L X X R T

4 7 8 2 X 7

3 X X X 1 8

1 2 X X X 6

1 1 2 4 4 7

S S 2 3 X X

 

//BFS

program __climbing;
const
  dil:array[1..9] of longint=(0,1,2,-1,-2,0,-1,1,0);
  djl:array[1..9] of longint=(-1,-1,-1,-1,-1,-2,-2,-2,-3);
  dir:array[1..9] of longint=(0,1,2,-1,-2,0,-1,1,0);
  djr:array[1..9] of longint=(1,1,1,1,1,2,2,2,3);
  maxq=1000000;
type
  node=record
    x,y,num:longint;
  end;
var
  q:array[0..maxq] of node;
  a:array[0..110,0..110] of longint;
  v:array[0..110,0..110,0..1] of longint;
  n,m,i,j,head,tail,k,x,y,tx,ty,p,ans:longint;
  s:ansistring;
  flag:boolean;
begin
  assign(input,'climbing.in');
  reset(input);
  assign(output,'climbing.out');
  rewrite(output);
  while (not eof) do
    begin
      tail:=0;
      head:=0;
      flag:=false;
      ans:=maxlongint;
      fillchar(a,sizeof(a),0);
      fillchar(v,sizeof(v),63);
      readln(n,m);
      for i:=1 to n do
        begin
          readln(s);
          s:=s+' ';
          for j:=1 to m do
            begin
              if (s[1]='X') then
                begin
                  a[i][j]:=-1;
                  delete(s,1,2);
                end
              else
                if (s[1]='S') then
                  begin
                    a[i][j]:=0;
                    v[i][j][0]:=0;
                    v[i][j][1]:=0;
                    inc(tail);
                    q[tail].x:=i;
                    q[tail].y:=j;
                    q[tail].num:=0;
                    inc(tail);
                    q[tail].x:=i;
                    q[tail].y:=j;
                    q[tail].num:=1;
                    delete(s,1,2);
                  end
              else
                if (s[1]='T') then
                  begin
                    a[i][j]:=500;
                    delete(s,1,2);
                  end
              else
                begin
                  k:=1;
                  while (s[k] in ['0'..'9']) do inc(k);
                  val(copy(s,1,k-1),a[i][j]);
                  delete(s,1,k);
                end;
            end;
        end;
      while (head<>tail) do
        begin
          inc(head);
          if (head=maxq) then head:=1;
          if (q[head].num=0) then
            begin
              x:=q[head].x;
              y:=q[head].y;
              for p:=1 to 9 do
                begin
                  tx:=x+dir[p];
                  ty:=y+djr[p];
                  if (tx>0)and(ty>0)and(tx<=n)and(ty<=m)and(a[tx][ty]<>-1) then
                    begin
                      if (a[tx][ty]=500) then
                        begin
                          flag:=true;
                          if (ans>v[x][y][0]) then ans:=v[x][y][0];
                          continue;
                        end;
                      if (v[tx][ty][1]>v[x][y][0]+a[tx][ty]) then
                        begin
                          v[tx][ty][1]:=v[x][y][0]+a[tx][ty];
                          inc(tail);
                          if (tail=maxq) then tail:=1;
                          q[tail].x:=tx;
                          q[tail].y:=ty;
                          q[tail].num:=1;
                        end;
                    end;
                end;
            end
          else
            begin
              x:=q[head].x;
              y:=q[head].y;
              for p:=1 to 9 do
                begin
                  tx:=x+dil[p];
                  ty:=y+djl[p];
                  if (tx>0)and(ty>0)and(tx<=n)and(ty<=m)and(a[tx][ty]<>-1) then
                    begin
                      if (a[tx][ty]=500) then
                        begin
                          flag:=true;
                          if (ans>v[x][y][1]) then ans:=v[x][y][1];
                          continue;
                        end;
                      if (v[tx][ty][0]>v[x][y][1]+a[tx][ty]) then
                        begin
                          v[tx][ty][0]:=v[x][y][1]+a[tx][ty];
                          inc(tail);
                          if (tail=maxq) then tail:=1;
                          q[tail].x:=tx;
                          q[tail].y:=ty;
                          q[tail].num:=0;
                        end;
                    end;
                end;
            end;
        end;
      if (flag) then writeln(ans) else writeln(-1);
    end;
  close(input);
  close(output);
end.

3.solve(solve.pas/c/cpp)

描述

dsqwwe每个月都有m(0<=m<=1000)元的零花钱,他现在有n(n<=300)项消费计划,每个消费计划消耗2种费用,一种是要花掉当前月的零花钱,另一种是要花掉下一个月的零花钱,每个月的零花钱不能超支,若一个月的零花钱不能用完,dsqwwe会把钱花在其他地方,也就是说,每个月剩余的零花钱不会留给下一个月。问dsqwwe想要完成他所有的消费计划最少需要几个月。

输入(solve.in):

第一行:m,n

接下来的n行,每行两个整数a,b,描述一种消费计划,a代表花掉当前月的钱的数目,b代表花掉下个月的钱的数目(a,b<=m)

输出(solve.out):

需要最少的月数

样例输入:

100 5
40 20
60 20
30 50
30 50
40 40

样例输出:

5

样例解释:

+------+-------+--------+---------+---------+--------+
|      |零花钱 |解决问题| 当前支付| 下月预支|月底结余|
|月份 | | | | |   |
+------+-------+--------+---------+---------+--------+
| 1    | 100   | 1, 2   | 40+60   | 0       | 0      |
| 2    | 100   | 3, 4   | 30+30   | 20+20   | 0      |
| 3    | 100   | -none- | 0       | 50+50   | 0      |
| 4    | 100   | 5      | 40      | 0       | 60     |
| 5    | 100   | -none- | 0       | 40      | 60     |
+------+-------+--------+---------+---------+--------+

 

//DP

program __solve;
var
  a,b,suma,sumb:array[0..310] of longint;
  ans,n,m,i,j,x:longint;
  f:array[0..310,0..310] of longint;
function min(a,b:longint):longint;
  begin
    if (a<b) then exit(a) else exit(b);
  end;
begin
  assign(input,'solve.in');
  reset(input);
  assign(output,'solve.out');
  rewrite(output);
  readln(m,n);
  for i:=1 to n do
    begin
      readln(a[i],b[i]);
      suma[i]:=suma[i-1]+a[i];
      sumb[i]:=sumb[i-1]+b[i];
    end;
  fillchar(f,sizeof(f),63);
  f[0][1]:=0;
  for i:=1 to n do
    for j:=1 to i do
      begin
        if (suma[i]-suma[i-j]>m) then break;
        if (sumb[i]-sumb[i-j]>m) then break;
        if (i=j) then
          begin
            f[i][j]:=f[i-j][1]+2;
            continue;
          end;
        for x:=1 to i-j do
          begin
            if (suma[i]-suma[i-j]<=m-sumb[i-j]+sumb[i-j-x]) then
              f[i][j]:=min(f[i][j],f[i-j][x]+1);
            f[i][j]:=min(f[i][j],f[i-j][x]+2);
          end;
      end;
  ans:=maxlongint;
  for i:=1 to n do
    ans:=min(ans,f[n][i]);
  writeln(ans);
  close(input);
  close(output);
end.