无压力水题模拟赛
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只保留了一种形状的玩具
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; }