T1:香烟
Description
你现在有n支香烟。香烟抽完后有香烟蒂头。k个香烟蒂头可以换一支新的香烟。(k > 1)现在一开始有n支香烟,问最多能抽多少支烟?只能利用你现有的烟,不能向别人借烟。
Input
一行,两个整数,n和k。两个整数均在longint范围之内,答案也在longint范围之内。
Output
输出只有一个数, 表示最多能抽多少支烟.
Sample Input
4 3
Sample Output
5
简要思路:这题只是一道简单的模拟题,连小学生都能切掉 ,只要注意用一个变量保存烟头数量,另一个变量保存剩余香烟数量即可。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n , k;
int ans , tem1 , tem2;//tem1剩余香烟数量,tem2烟头数量
inline void read( int & res ) {
res = 0;
int pd = 1;
char a = getchar();
while ( a < '0' || a > '9' ) {
if ( a == '-' ) {
pd = -pd;
}
a = getchar();
}
while ( a >= '0' && a <= '9' ) {
res = ( res << 1 ) + ( res << 3 ) + ( a - '0' );
a = getchar();
}
res *= pd;
return;
}
int main () {
read(n);
read(k);
ans = n;
tem1 = n;
tem2 = tem1 / k;
while( tem2 ) {
tem1 %= k;
tem1 += tem2;
ans += tem2;
tem2 = tem1 / k;
}
printf("%d",ans);
return 0;
}
T2:背包问题
Description
从T组物品中选出一些物品,放入背包中,求剩余空间的最小值。
限制条件:从每组物品中挑选物品必须要选取连续的一段。就是说,如果这组物品共有n个: 物品1、物品2、物品3、…、物品n,那么只能选取物品i、物品i+1、…、物品j,其中1<=i<=j<=n,或者不选。
Input
第一行为两个用空格隔开的正整数v和T。表示背包的空间和物品的组数。接下来有T行,每行先是一个正整数ni,表示这组物品有ni个,然后ni个正整数,表示每个物品的大小。
Output
仅一个数,表示剩余空间的最小值。
Sample Input
100 3 3 7 6 8 2 80 70 4 101 108 103 150
Sample Output
6
Hint
【样例说明】
第1组选6、8,第2组选80,第3组不选。
【限制】
60%的数据满足:1 <= ni <= 10
100%的数据满足:1 <= ni <= 100,1<=v<=5000,1<=T<=10
简要思路:这道题很多人给表示背包的数组赋了实际的值,可我用的不是这个方法。我用
来表示将前
组物品放入背包后能否达到占用大小为
的空间,值为1表示可以,为0表示不可以。用
表示第
组物品前
个物品占用的总空间。状态转移方程为
,这里max用来在0和1之间取1。
最后倒序枚举
,遇到的第一个为1的数所对应的
就是本题的答案。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int v , t , tem;
int f[11][5005] , sum[11][105] , n[11];
inline void read( int & res ) {
res = 0;
int pd = 1;
char a = getchar();
while ( a < '0' || a > '9' ) {
if ( a == '-' ) {
pd = -pd;
}
a = getchar();
}
while ( a >= '0' && a <= '9' ) {
res = ( res << 1 ) + ( res << 3 ) + ( a - '0' );
a = getchar();
}
res *= pd;
return;
}
int main () {
read(v);
read(t);
for ( register int i = 0 ; i <= t ; ++i ) {
f[i][0] = 1;
}
for ( register int i = 1 ; i <= t ; ++i ) {
read(n[i]);
for ( register int j = 1 ; j <= n[i] ; ++j ) {
read(tem);
sum[i][j] = sum[i][j - 1] + tem;
}
}
for ( register int i = 1 ; i <= t ; ++i ) {
for ( register int j = 0 ; j <= v ; ++j ) {
for ( register int k = 0 ; k <= n[i] ; ++k ) {
for ( register int l = k ; l <= n[i] ; ++l ) {
if ( j + sum[i][l] - sum[i][k] <= v ) {
f[i][j + sum[i][l] - sum[i][k]] = max( f[i][j + sum[i][l] - sum[i][k]] , f[i - 1][j] );
}
}
}
}
}
int ans = 0;
for ( register int i = v ; i >= 0 ; --i ) {
if ( f[t][i] ) {
ans = i;
break;
}
}
printf("%d",v-ans);
return 0;
}
T3:破碎的路径
Description
比尔去很多地方旅游过。他在旅游的同时留下了很多简短的旅行笔记。笔记的形式是这样的:
出发地 目的地
如下面就是三条合法的note:
SwimmingPool OldTree
BirdsNest Garage
Garage SwimmingPool
在某一次搬家的时候,比尔的笔记本不小心散架了。于是他的笔记的顺序被完全打乱了。他想请你帮个忙,帮他把这些笔记的顺序整理好,先写的笔记在前面。幸运的是,同一个地方比尔至多只去过一次。也就是说,在这些笔记当中,一个地方至多出现两次,一次作为目的地,一次作为出发地。
Input
第一行是一个整数n,表示笔记的条数。N <= 12000。接下来有n行,每行一条笔记。笔记的两个单词的长度都不会超过15,两个单词之间以一个空格分隔。
Output
输出整理好顺序的笔记.
Sample Input
3 SwimmingPool OldTree BirdsNest Garage Garage SwimmingPool
Sample Output
BirdsNest Garage Garage SwimmingPool SwimmingPool OldTree
Hint
【限制】
对于50%的数据,n <= 1000。
对于100%的数据,n <= 12000。
简要思路:根据题意描述,鉴于旅行的比尔不会飞,再加上他只去一个地方一次,我们不难发现他旅行的路线是一条链,用拓扑大法即可,对于字符串用map即可,也有用哈希的,不过输出时要枚举,时间复杂度稍大。
输出时在jzoj必须将字符串一次输出,不能一个字符一个字符地输出,否则会被误判 ,具体原因我也不知道了(我就这样被坑了100分啊qwq )。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <map>
using namespace std;
int n , bcnt;
string s1 , s2;
map < string , int > f1;
map < int , string > f2;
int inde[15005] , to[15005];
int main () {
scanf("%d",&n);
for ( int i = 1 ; i <= n ; ++i ) {
cin >> s1;
cin >> s2;
if ( !f1[s1] ) {
f1[s1] = ++bcnt;
f2[bcnt] = s1;
}
if ( !f1[s2] ) {
f1[s2] = ++bcnt;
f2[bcnt] = s2;
}
inde[f1[s2]]++;
to[f1[s1]] = f1[s2];
}
int pos = 0;
for ( int i = 1 ; i <= bcnt ; ++i ) {
if ( !inde[i] ) {
pos = i;
break;
}
}
while ( to[pos] ) {
cout << f2[pos] << " " << f2[to[pos]] << endl;
pos = to[pos];
}
return 0;
}
T4:无线网络
Description
有一个由n台计算机组成的无线网络。(n <= 1001),正常情况下,每台计算机都能跟与它距离不超过d的任何计算机通讯(d <= 20000)。地震发生了。所有的计算机都陷入瘫痪。专家们试着一台一台地修复计算机,以恢复整个无线网络。有时在修复的过程中,他们需要测试一下某两台计算机能否通讯(如果他们能通过别的正常的计算机进行通讯,也算他们之间可以通讯,即“能否通讯”可以是间接的)。
你的任务,就是模拟修复网络的过程,并回答“能否通讯”的询问。
Input
第一行两个整数,N和d,N表示计算机的数目,d表示两台计算机直接可直接通讯的最大距离。接下来的N行,每行两个整数Xi,Yi,表示每台计算机的坐标。接下来有许多行,每行都是一个操作(或者是修复操作,或者是询问操作)。
操作的格式如下:
O p (1 <= p <= N) 修复操作,表示修复编号为p的电脑;
S p q (1 <= p, q <= N) 询问操作,询问编号为p和编号为q的电脑能否通讯。
如果一台电脑尚未被修复,则它不能和任何电脑通讯。
Output
对于每个询问操作:如果能够通讯,输出一行SUCCESS;如果无法通讯,输出一行FAIL
Sample Input
4 1 0 1 0 2 0 3 0 4 O 1 O 2 O 4 S 1 4 O 3 S 1 4
Sample Output
FAIL SUCCESS
Hint
【限制】
对于50%的数据,N <= 300, 操作次数 <= 10000;
对于100%的数据,N <= 1001, 操作次数 <= 300000。
简要思路:这题用并查集即可,预处理时可以预处理出任两点之间的距离。每当一个点修好后,枚举其他所有点,如果与当前点的距离小于 就将两个点放在一个集合中。在判断两个电脑能否通讯时,除了要判断它们是否在一个集合中,还要注意两个电脑本身是否已修好。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#define N 1005
using namespace std;
int fa[N] , p[N];
double dis[N][N];
char ss;
int n , d;
struct node{
int x;
int y;
}nod[N];
inline void read( int & res ) {
res = 0;
int pd = 1;
char a = getchar();
while ( a < '0' || a > '9' ) {
if ( a == '-' ) {
pd = -pd;
}
a = getchar();
}
while ( a >= '0' && a <= '9' ) {
res = ( res << 1 ) + ( res << 3 ) + ( a - '0' );
a = getchar();
}
res *= pd;
return;
}
inline int find( int x ) {
if ( x == fa[x] ) {
return x;
} else {
fa[x] = find( fa[x] );
return fa[x];
}
}
inline void unio( int x , int y ) {
int fx = find(x);
int fy = find(y);
if ( fx != fy ) {
fa[fx] = fy;
}
return;
}
inline double cnt( int x1 , int y1 , int x2 , int y2 ) {
return sqrt( (double)( x2 - x1 ) * (double)( x2 - x1 ) + (double)( y2 - y1 ) * (double)( y2 - y1 ) );
}
int main () {
scanf("%d%d",&n,&d);
for ( int i = 1 ; i <= n ; ++i ) {
fa[i] = i;
p[i] = 0;
scanf("%d%d",&nod[i].x,&nod[i].y);
for ( int j = 1 ; j <= i - 1 ; ++j ) {
dis[i][j] = dis[j][i] = cnt( nod[i].x , nod[i].y , nod[j].x , nod[j].y );
}
}
int x , y;
while ( scanf("%c ",&ss) != EOF ) {
switch(ss) {
case 'O' : {
scanf("%d",&x);
p[x] = 1;//判断电脑是否已修好
for ( int i = 1 ; i <= n ; ++i ) {
if ( p[i] && i != x && dis[i][x] <= d ) {
unio( x , i );
}
}
break;
}
case 'S' : {
scanf("%d%d",&x,&y);
int fx = find(x);
int fy = find(y);
if ( fx == fy && p[x] && p[y] ) {
printf("SUCCESS\n");
} else {
printf("FAIL\n");
}
break;
}
}
}
return 0;
}