无压力水题模拟赛

Day1

题目名称

Little Rooks

Diablo Items

paid Roads

可执行文件名

Rooks

Items

Roads

输入文件名

Rooks.in

Items.in

Roads.in

输出文件名

Rooks.out

Items.out

Roads.out

每个测试点时限

1s

1s

1s

测试点个数

10

10

10

每个测试点分值

10

10

10

内存限制

128M

128M

128M

提交源程序须加后缀

对于Pascal语言

rooks.pas

Items.pas

Roads.pas

对于C语言

rooks.c

Items.c

Roads.c

对于C++语言

rooks.cpp

Item.cpp

Roads.cpp

文件名均小写。

 

 

Little Rooks

【题目描述】

给定一个n*n的方形棋盘,和k个棋子,这k个棋子在国际象棋中被称为——rooks,他和中国象棋中的车有着相同的攻击规则。问,在这个棋盘上,有多少种方案放下这k个棋子,并使得他们不互相攻击。

【输入格式】

输入有多组,每组数据仅一行两个用空格隔开的整数n和k,含义如上。0 0代表文件的结束。

【输出格式】

对于每组输入数据有且仅有一个整数代表可以成立的放置的方案数。

【输入样例】

4 4

0 0

【输出样例】

24

【数据范围】

所有的答案在int64以内

N<=11

K<=N^2

 

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int n,k;
long long C(int m,int n){
     long long tot=1;
     for (long long i=k+1;i<=n;i++){
         tot*=i;
     }
     for (int i=n-k;i>1;i--){
         tot/=i;
     }
     return tot;
}
long long A(int n){
     long long tot=1;
     for (int i=2;i<=n;i++) tot*=i;
     return tot;
}
int main(){
    freopen("rooks.in","r",stdin);
    freopen("rooks.out","w",stdout);
    while (cin>>n>>k){
          if (n==0 && k==0) break;
          if (k>n) cout<<0<<endl;else
          cout<<C(k,n)*C(k,n)*A(k)<<endl;
    }
    return 0;
}

 

Paid Roads

【题目描述】

这里有一个地图,嗯~准确的说是一个藏宝图。你在1号点,宝藏在n号点,所有的点编号1~n,这块宝底的地形是很奇怪的,每两个点之间有两条通路,两个通路的长度是不一样的,可能会有一条比较短,你可以任选一条,但是其中一条你只有在之前经过某个点的时才能通行,就好像这条路的通行证在那个点上一样。现在想知道怎么样走才能以最短的路程到达藏宝点。

【输入格式】

第一行两个用空格隔开的整数n和m分别表示节点的编号个数和该藏宝点路径条数。

第二行到第m+1行每行5个整数a,b,c,la,lb描述从a点到b点的有向路,la表示之前经过c后,可以从a到b的路径长度,lb表示随时都可以同行的a到b的路径长度。

【输出格式】

一行一个整数表示的是从1到n的最短路程。如果没有路输出‘impossible’。

【输入样例】

4 5

1 2 1 10 10

2 3 1 30 50

3 4 3 80 80

2 1 2 10 10

1 3 2 10 50

【输出样例】

110

【数据范围】

N,m<=10

la,lb<=maxlongint

 

#include <cstdio>
#include <cstring>
#include <iostream>
#define INF 2147483647
using namespace std;
int v[20];
int n,m,ans;
struct edge{
       int x,y,la,lb,next;
}e[100000];
int k[20];
int tot;
void add(int a,int b,int c,int la,int lb){
     e[++tot].x=b;
     e[tot].y=c;
     e[tot].la=la;
     e[tot].lb=lb;
     e[tot].next=k[a];
     k[a]=tot;
}
void dfs(int x,int sum){
     if (x==n){
               if (ans>sum) ans=sum;
               return;
     }
     for (int t=k[x];t;t=e[t].next){
         if (v[e[t].x]<4){
                          ++v[e[t].x];
                          if (v[e[t].y]) dfs(e[t].x,sum+e[t].la);
                          else dfs(e[t].x,sum+e[t].lb);
                          --v[e[t].x];
         }
     }
}
int main(){
    freopen("roads.in","r",stdin);
    freopen("roads.out","w",stdout);
    cin>>n>>m;
    for (int i=1;i<=m;i++){
        int a,b,c,la,lb;
        cin>>a>>b>>c>>la>>lb;
        add(a,b,c,la,lb);
    }
    v[1]=1;
    ans=INF;
    dfs(1,0);
    if (ans<INF) cout<<ans<<endl;else cout<<"impossible"<<endl;
    return 0;
}

 

 

Diablo Items

【题目描述】

Diablo II中,有两种物品:普通物品和魔法物品。显然,魔法物品有普通物品没有的神奇力量。

魔法物品和普通物品都可以被卖掉:一个普通物品只有一个价值Pi;而一个魔法物品有两个价值Pi1和Pi2,当使用购买的魔法卷轴鉴定过这个魔法物品以后,它的价值就变为Pi2,否则它只具有Pi1的价值(当然Pi2一定要大于Pi1)。鉴定一个魔法物品需要花费Q来购买一个魔法卷轴,每个魔法卷轴只能使用一次。

你的手中有一些物品。对于普通物品,你已经知道了它们的价值Pi;对于魔法物品,你已经知道了它们的价值Pi1和Pi2。

现在,你想要把它们全部卖掉,以得到最大的收益。

注意:

1. 开始时,你的收中没有钱,无法购买卷轴。

2. 开始时,没有任何魔法物品被卷轴鉴定过。

3. 如果你的手中有足够多的钱,你可以购买足够多的卷轴,但你手中的剩余的钱不能为负。

【输入格式】

每个测试点有多组测试数据:

对于每组测试数据:

第一行两个整数N和Q,N表示拥有物品的数量,Q表示购买一个魔法卷轴的花费。

第二行..第N+1行每行有一个整数或两个整数,如果为一个数,表示这件物品是普通物品,价值为Pi,否则为魔法物品两个价值为Pi1和Pi2。

【输出格式】

对于每组测试数据:

一个整数,即最大的收益。

【样例输入】

2 10

5

8

2 10

10

10 100

【样例输出】

13

100

【数据范围】

0<=N<=1000

Q<=30000

Pi<=10000

Pi1<Pi2<=10000

 

#include <cstdio>
#include <cstring>
int n,p,m;
int a[1100][4];
int f[11000];
int cost;
inline int min(int a,int b){
    if (a<0) return b;
    if (b<0) return a;
    if (a<b) return a;else return b;
}
void init(){
     m=0;
     cost=0;
     for (int i=1;i<=n;i++){
         int x=0;
         bool flag=false;
         char c=getchar();
         while (c<'0' && c>'9') c=getchar();
         while (c!='\n'){
               x=x*10+c-'0';
               c=getchar();
               if (c==' '){
                        flag=true;
                        a[++m][1]=x;
                        x=0;
                        c=getchar();
               }
         }
         if (!flag) cost+=x;
         else{
              a[m][2]=x;
              a[m][3]=x-a[m][1]-p;
              if (x-p<a[m][1]){
                               cost+=a[m][1];
                               m--;
              }
         }
     }
}
int run(){
    int sum=0;
    if (cost>=p || m==0){
                 sum=cost;
                 for (int i=1;i<=m;i++){
                     sum+=a[i][2]-p;
                 }
                 return sum;
    }
    int need=-cost+p;
    memset(f,255,sizeof(f));
    f[0]=0;
    for (int i=1;i<=m;i++){
        for (int j=need;j>=0;j--){
            if (f[j]!=-1){
                          int next=j+a[i][1];
                          next=min(next,need);
                          f[next]=min(f[next],f[j]+a[i][3]);
            }
        }
    }
    if (f[need]==-1){
                     sum=cost;
                     for (int i=1;i<=m;i++){
                         sum+=a[i][1];
                     }
                     return sum;
    }else{
          sum+=cost;
          for (int i=1;i<=m;i++){
              sum+=a[i][2]-p;
          }
          return sum-f[need];
    }
}
int main(){
    freopen("items.in","r",stdin);
    freopen("items.out","w",stdout);
    while (scanf("%d%d\n",&n,&p)!=EOF){
          init();
          printf("%d\n",run());
    }
    return 0;
}

 

 

无压力水题模拟赛

Day2

题目名称

MEETING

toy

lights

可执行文件名

MEETING

toy

lights

输入文件名

MEETING.IN

toy.in

lights.in

输出文件名

MEETING.OUT

toy.out

lights.out

每个测试点时限

1s

1s

1s

测试点个数

10

10

10

每个测试点分值

10

10

10

内存限制

128M

128M

128M

提交源程序须加后缀

对于Pascal语言

MEETING.pas

toy.pas

lights.pas

对于C语言

MEETING.c

toy.c

lights.c

对于C++语言

MEETING.cpp

toy.cpp

lights.cpp

文件名均小写。

Meeting

【题目描述】

Spray 和 Ray 想要在X时刻和Y时刻之间的某个时候会面,但是这两个人都不是很准时的……所以它们没有商定会面的确切时间。但是它们商量好,谁要是先到了,就等对方Z分钟时间。但是它们两个都会在X点和Y点之间的某时刻出现,只是不一定会碰到。

现在,请你计算他们两个碰面的概率。

【输入格式】

输入数据有多组测试数据

每组测试数据包含两个整数X和Y(0<=x<y<=24)和一个实数Z(0<Z<=60*(Y-X))

【输出格式】

对于每组测试数据

输出一行,为计算出的概率,保留小数点后6位,第7位四舍五入。

【输入样例】

11 12 20

【输出样例】

0.555556

 

#include <cstdio>
#include <iomanip>
#include <iostream>
using namespace std;
double c;
int a,b;
int main(){
    freopen("meeting.in","r",stdin);
    freopen("meeting.out","w",stdout);
    while (scanf("%d %d %lf",&a,&b,&c)!=EOF){
          double t=b-a-c/60.0;
          double ans=((b-a)*(b-a)-t*t)/(b-a)/(b-a);
          printf("%.6lf\n",ans);
    }
    return 0;
}

 

Toy Bricks

【题目描述】

Ray又在NPC问题了:这里有一个箱子,还有若干个玩具。

我们可以假设玩具的数量是没有上限的。我们还知道这个箱子是不规则的,或者可以说,他的外形比较像一个矩形,但是内部却有很多突起,这些突起很可恶,他可以一直突到玩具的顶盖部。为了简化这个NPC问题,Ray只保留了一种形状的玩具
clip_image001
Ray想知道对于一个给定的箱子,最多可以放下多少个这样的玩具。

【输入格式】

第一行两个用空格隔开的整数n 和 m 表示玩具想的长度和宽度

第二行到第n+1行,每行m个用空格隔开的字符‘#’’.‘;’#’表示这里是一个障碍物。’.’表示这里可以放东西。

【输出格式】

一行一个整数表示最多的玩具个数

【输入样例】

5 4

#.#.

…#

#..#

#...

##.#

【输出样例】

2

【数据范围】

0<=n<=100

0<=m<=10

 

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
int T;
int n,m;
int st[130];
int tot;
int num[110];
int dp[110][130][130];
int cur[110];
int ans;
int max(int a,int b){return a>b?a:b;}
bool ok(int i){//判断可行状态 
     if ((i & (i << 1)) || (i & (i >> 1))) return 0;
     for (int k=1;k<=m;k++){
         if ((i & (1 << (k-1))) && (i & (1 << (k+1)))) return 0;
     }
     return 1;
}
void build(){//枚举得到所有可行状态 
     for (int i=0;i<1 << m;i++){
         if (!(i & 1) && !(i & (1 << (m-1))))
         if (ok(i)) st[++tot]=i;
     }
}
int getnum(int x){//得到一个状态中放置的玩具个数 
    int cnt=0;
    while (x){
          ++cnt;
          x &= (x-1);
    }
    return cnt;
}
bool fit(int x,int i){//判断这一行和上一行(下一行) 的障碍是否冲突 
     if (cur[i] & x) return 0;
     return 1;
}
bool fit2(int x,int i){//判断这一行的状态和这一行的障碍是否冲突 
     if (cur[i] & x) return 0;
     if (cur[i] & (x >> 1)) return 0;
     if (cur[i] & (x << 1)) return 0;
     return 1;
}
bool check(int a,int b){//判断这一行和上一行的状态是否可行 
     for (int i=1;i<m-1;i++){
         if (a & (1 << i))
            if ((b & (1 << i)) || (b & (1 << (i-1))) || (b & (1 << (i+1)))) return 0;
     }
     return 1;
}
bool check2(int a,int b){//判断这一行的状态和前两行的状态是否可行 
     if (a & b) return 0;
     return 1;
}
int main(){
    freopen("toy.in","r",stdin);
    freopen("toy.out","w",stdout);
    while (scanf("%d%d\n",&n,&m)!=EOF){
          tot=0;
          memset(cur,0,sizeof(cur));
          build();
          for (int i=1;i<=n;i++){
              for (int j=1;j<=m;j++){
                  char c;
                  scanf("%c",&c);
                  if (c=='#') cur[i]+=(1 << (j-1));
              }
              scanf("\n");
          }
          memset(dp,-1,sizeof(dp));
          for (int i=1;i<=tot;i++){
              num[i]=getnum(st[i]);
              if (fit(st[i],1) && fit2(st[i],2)){
                                dp[2][1][i]=num[i];
              }
          }
          for (int i=3;i<=n;i++){
              for (int j=1;j<=tot;j++){
                  if (fit2(st[j],i))
                  for (int k=1;k<=tot;k++){
                      if (fit2(st[k],i-1) && fit(st[j],i-1) && fit(st[k],i))
                      if (check(st[j],st[k]))
                      for (int l=1;l<=tot;l++){
                          if (dp[i-1][l][k]!=-1)
                          if (check2(st[l],st[j]))
                          dp[i][k][j]=max(dp[i][k][j],dp[i-1][l][k]+num[j]);
                      }
                  }
              }
          }
          for (int i=1;i<=tot;i++){
              if (fit2(st[i],n-1) && fit(st[i],n)) ans=max(ans,dp[n][i][1]);
          }
          printf("%d\n",ans);
    }
    return 0;
}

 

Lights

【题目描述】

Spray来到了zz城。这个城市的的交通规则非常奇怪,城市公路通过路口相连,两个不同路口之间最多只有一条直达公路。公路的起止点不会是同一路口。在任意一条公路上顺不同方向走所需时间相同。每一个路口都有交通灯,这些交通灯在某一时刻要么是蓝色,要么是紫色。同一个灯上2个颜色的维持时间受到定期调控,总是蓝色持续一段时间,紫色持续一段时间。交通规则规定两个路口可以通车仅当公路两边交通灯的颜色相同(也就是说只要你在A路口看见A与B的交通灯颜色相同,那么就可以走上A-B这条路并到达B路口)。交通工具可以在路口等候。

现在Spray有这个城市的地图,包含:

1. 通过所有公路需要的时间(整数)

2. 每个路口交通灯两种颜色的持续时间(整数)

3. 每个路口交通灯的初始颜色以及初始颜色的持续时间(整数).
你的任务是帮Spray找到一条从起点到终点的最快路径(保证路径唯一)。
【输入数据】

第一行包含两个整数: 起点和终点的编号.

第二行包含两个整数: N, M. (2 ≤ N ≤ 300 ,1 ≤ M ≤ 14000)

接下来 N 行描述 N 个路口的情况.

第i+2行 是 i 号路口的信息: Ci, riC, tiB, tiP 。

其中字符 Ci 要么是“B”代表蓝色,要么是“P”代表紫色,表示 i 的起始颜色. riC, tiB, tiP 分别表示初始颜色,蓝色,紫色的持续时间,

(1 ≤ tiC ≤ 100 . 1 ≤ riC ≤ tiC )

最后的 M 行表示关于 M 条公路的信息。包含: i, j, lij 。i 和 j 号路口被这条路连接. lij 是通过i到j这条公路需要的时间。(1 ≤ lij ≤ 100)

【输出数据】

如果存在最短路径:

第一行输出最短时间。

第二行是一个对应第一行答案的路口编号表,从起点到终点输出路口编号,数字之间用空格隔开(即输出路径方案)。
如果不存在,直接输出“0”。

【样例输入】

1 4
4 5
B 2 16 99
P 6 32 13
P 2 87 4
P 38 96 49
1 2 4
1 3 40
2 3 75
2 4 76
3 4 77

【样例输出】

127
1 2 4

 

 

#include <cstdio>
#include <cstring>
#include <cstdlib>
#define M 100000
int n,m;
int st,en;
struct NODE{
       int c,b,p,r;
}node[310];
struct EDGE{
       int x,next,l;
}edge[28100];
int k[310];
int f[M];
int d[310];
bool v[310];
int tot,sum;
int pre[310];
int len[310];
int ans;
int min(int a,int b){return a<b?a:b;}
void add(int a,int b,int c){
     edge[++tot].x=b;
     edge[tot].l=c;
     edge[tot].next=k[a];
     k[a]=tot;
}
int wait(int x,int y,int t){
    int i,j;
    //初始状态比较 
    int tt=t;
    if (tt<node[x].r) i=node[x].c;
    else{
         tt=(t-node[x].r) % (node[x].p+node[x].b);
         int dd;
         if (node[x].c==0) dd=node[x].b;else dd=node[x].p;
         if (tt>=0 && tt<dd) i=!node[x].c;else i=node[x].c;
    }
    //------------------------------
    tt=t;
    if (tt<node[y].r) j=node[y].c;
    else{
         tt=(t-node[y].r) % (node[y].b+node[y].p);
         int dd;
         if (node[y].c==0) dd=node[y].b;else dd=node[y].p;
         if (tt>=0 && tt<dd) j=!node[y].c;else j=node[y].c;
    }
    if (i==j) return 0;
    //不同进入第一次变灯 
    int tx,ty;
    if (t<node[x].r) tx=node[x].r;
    else{
         int mid=(t-node[x].r) % (node[x].b+node[x].p);
         int dd;
         if (node[x].c==0) dd=node[x].b;else dd=node[x].p;
         if (mid>=0 && mid<dd) tx=t-mid+dd;
         else tx=t-mid+(node[x].b+node[x].p);
    }
    //------------------------------
    if (t<node[y].r) ty=node[y].r;
    else{
         int mid=(t-node[y].r) % (node[y].b+node[y].p);
         int dd;
         if (node[y].c==0) dd=node[y].b;else dd=node[y].p;
         if (mid>=0 && mid<dd) ty=t-mid+dd;
         else ty=t-mid+(node[y].b+node[y].p);
    }
    if (tx!=ty) return min(tx,ty)-t;
    //第一次编订后仍不同进入第二次变灯 
    int mid=(tx-node[x].r) % (node[x].b+node[x].p); 
    int dd;
    if (node[x].c==0) dd=node[x].b;else dd=node[x].p;
    if (mid>=0 && mid<dd) tx=tx-mid+dd;
    else tx=tx-mid+(node[x].b+node[x].p);
    //------------------------------
    mid=(ty-node[y].r) % (node[y].b+node[y].p);
    if (node[y].c==0) dd=node[y].b;else dd=node[y].p;
    if (mid>=0 && mid<dd) ty=ty-mid+dd;
    else ty=ty-mid+(node[y].b+node[y].p);
    if (tx!=ty) return min(tx,ty)-t;
    //第二次变灯后仍不同进入第三次变灯
    mid=(tx-node[x].r) % (node[x].b+node[x].p); 
    if (node[x].c==0) dd=node[x].b;else dd=node[x].p;
    if (mid>=0 && mid<dd) tx=tx-mid+dd;
    else tx=tx-mid+(node[x].b+node[x].p);
    //------------------------------
    mid=(ty-node[y].r) % (node[y].b+node[y].p);
    if (node[y].c==0) dd=node[y].b;else dd=node[y].p;
    if (mid>=0 && mid<dd) ty=ty-mid+dd;
    else ty=ty-mid+(node[y].b+node[y].p);
    if (tx!=ty) return min(tx,ty)-t;
    //第三次编订后仍不同进入第四次变灯
    mid=(tx-node[x].r) % (node[x].b+node[x].p); 
    if (node[x].c==0) dd=node[x].b;else dd=node[x].p;
    if (mid>=0 && mid<dd) tx=tx-mid+dd;
    else tx=tx-mid+(node[x].b+node[x].p);
    //------------------------------
    mid=(ty-node[y].r) % (node[y].b+node[y].p);
    if (node[y].c==0) dd=node[y].b;else dd=node[y].p;
    if (mid>=0 && mid<dd) ty=ty-mid+dd;
    else ty=ty-mid+(node[y].b+node[y].p);
    if (tx!=ty) return min(tx,ty)-t;
    //第四次编订后仍不同进入第五次变灯
    mid=(tx-node[x].r) % (node[x].b+node[x].p);
    if (node[x].c==0) dd=node[x].b;else dd=node[x].p;
    if (mid>=0 && mid<dd) tx=tx-mid+dd;
    else tx=tx-mid+(node[x].b+node[x].p);
    //------------------------------
    mid=(ty-node[y].r) % (node[y].b+node[y].p);
    if (node[y].c==0) dd=node[y].b;else dd=node[y].p;
    if (mid>=0 && mid<dd) ty=ty-mid+dd;
    else ty=ty-mid+(node[y].b+node[y].p);
    if (tx!=ty) return min(tx,ty)-t;
    //无法通行 
    return -1;
}
//最短路求解 
void SPFA(){
     int head=0,tail=1;
     memset(d,63,sizeof(d));
     memset(v,0,sizeof(v));
     d[st]=0;
     v[st]=true;
     f[tail]=st;
     while (head!=tail){
           head++;
           if (head==M) head=1;
           int x=f[head];
           v[x]=false;
           for (int t=k[x];t;t=edge[t].next){
               int tmp=wait(x,edge[t].x,d[x]);
               if (tmp!=-1 && d[edge[t].x]>d[x]+tmp+edge[t].l){
                                              d[edge[t].x]=d[x]+tmp+edge[t].l;
                                              pre[edge[t].x]=x;
                                              if (!v[edge[t].x]){
                                                              v[edge[t].x]=true;
                                                              tail++;
                                                              if (tail==M) tail=1;
                                                              f[tail]=edge[t].x;
                                              }
               }
           }
     }
     ans=d[en];
}    
int main(){
    freopen("lights.in","r",stdin);
    freopen("lights.out","w",stdout);
    scanf("%d%d\n",&st,&en);
    if (st==en){
                printf("0\n%d\n",st);
                return 0;
    }
    scanf("%d%d\n",&n,&m);
    for (int i=1;i<=n;i++){
        char c;
        scanf("%c%d%d%d\n",&c,&node[i].r,&node[i].b,&node[i].p);
        node[i].c=('B'==c);
    }
    for (int i=1;i<=m;i++){
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        add(x,y,z);
        add(y,x,z);
    }
    SPFA();
    if (ans>100000){printf("0\n");return 0;}
    printf("%d\n",ans);
    len[++sum]=en;
    int t=pre[en];
    while (t){
          len[++sum]=t;
          t=pre[t];
    }
    for (int i=sum;i>1;i--) printf("%d ",len[i]);
    printf("%d\n",len[1]);
    return 0;
}