河南省第五届大学生程序设计竞赛
Problem A: 奇怪的排序 Time Limit: 1 Sec Memory Limit: 128 MB Submit: 22 Solved: 13 [Submit][Status][Web Board] Description 最近,Dr. Kong 新设计一个机器人Bill。这台机器人很聪明,会做许多事情。惟独对自然数的理解与人类不一样,它是从右往左读数。比如,它看到123时,会理解成321。让它比较23与15哪一个大,它说15大。原因是它的大脑会以为是32与51在进行比较。再比如让它比较29与30,它说29大。
给定Bill两个自然数A和B,让它将 [A,B] 区间中的所有数按从小到大排序出来。你会认为它如何排序?
Input 第一行: N 表示有多少组测试数据。
接下来有N行,每一行有两个正整数A B 表示待排序元素的区间范围。
2<=N<=5 1<=A<=B<=200000 B-A<=50。
Output 对于每一行测试数据,输出一行,为所有排好序的元素,元素之间有一个空格。
Sample Input 2 8 15 22 39 Sample Output 10 8 9 11 12 13 14 15 30 31 22 32 23 33 24 34 25 35 26 36 27 37 28 38 29 39
处理一下排序就好。。
#include
using namespace std;
int T;
int s,e;
class A
{
public:
int now,ori;
};
bool operator < (const A &a,const A &b)
{
return a.now<b.now;
}
A a[1000000],b[1000000];
int n=0;
A calc(int t)
{
if(a[t].now)return a[t];
int tt=a[t].ori;
while(tt)
{
a[t].now*=10;
a[t].now+=(tt%10);
tt/=10;
}
return a[t];
}
int main()
{
freopen("in.txt","r",stdin);
while(~scanf("%d",&T))
{
while(T--)
{
n=0;
scanf("%d %d",&s,&e);
for(int i=s;i<=e;i++)
{
a[i].ori=i;
b[n++]=calc(i);
}
sort(b,b+n);
for(int i=0;i!=n;i++)
{
if(i)printf(" ");
printf("%d",b[i].ori);
}
printf("
");
}
}
return 0;
}
Problem B: 最强DE战斗力 Time Limit: 1 Sec Memory Limit: 128 MB Submit: 30 Solved: 8 [Submit][Status][Web Board] Description 春秋战国时期,赵国地大物博,资源非常丰富,人民安居乐业。但许多国家对它虎视眈眈,准备联合起来对赵国发起一场战争。
显然,面对多个国家的部队去作战,赵国的兵力明显处于劣势。战斗力是决定战争成败的关键因素,一般来说,一支部队的战斗力与部队的兵力成正比。但当把一支部队分成若干个作战队伍时,这个部队的战斗力就会大大的增强。
一支部队的战斗力是可以通过以下两个规则计算出来的:
1.若一支作战队伍的兵力为N,则这支作战队伍的战斗力为N;
2.若将一支部队分为若干个作战队伍,则这支部队的总战斗力为这些作战队伍战斗力的乘积。
比如:一支部队的兵力为5时的战斗力分析如下:
情况
作战安排
总的战斗力
1
1,1,1,1,1(共分为5个作战队伍)
11111=1
2
1,1,1,2 (共分为4个作战队伍)
111*2=2
3
1,2,2 (共分为3个作战队伍)
122=4
4
1,1,3 (共分为3个作战队伍)
113=3
5
2,3 (共分为2个作战队伍)
2*3=6
6
1,4 (共分为2个作战队伍)
1*4=4
7
5 (共分为1个作战队伍)
5=5
显然,将部队分为2个作战队伍(一个为2,另一个为3),总的战斗力达到最大!
Input 第一行: N 表示有N组测试数据。 (2<=N<=5)
接下来有N行,每行有一个整数Ti 代表赵国部队的兵力。 (1 <= Ti <= 1000)i=1,…N
Output 对于每一行测试数据,输出占一行,仅一个整数S, 表示作战安排的最大战斗力。
Sample Input 2 5 4 Sample Output 6 4
本来以为是dp,打个表就好了,然而打完一看,越界了。
1000个人,假如全2人两人分,是2^500,好吧不是DP而是个大数问题,那么问题来了。 是不是有最优的分解方式呢? 具体分析见:https://blog.csdn.net/u012349696/article/details/45098941 感谢大佬。
之后就模拟一下大数相乘就好。
#include
using namespace std;
const int maxn=10000;
int T,n;
int a[maxn];
int cnt=0;
void f(int t)
{
for(int i=0;i!=cnt;i++)
{
a[i]*=t;
}
int cnt2=0;
while(cnt2<=cnt)
{
if(a[cnt2]>9)
{
int nextt=cnt2+1;
a[nextt]+=(a[cnt2]/10);
a[cnt2]%=10;
if(nextt>=cnt)cnt++;
}
cnt2++;
}
}
int main()
{
freopen("in.txt","r",stdin);
while(~scanf("%d",&T))
{
while(T--)
{
memset(a,0,sizeof(a));
a[0]=1;
cnt=1;
scanf("%d",&n);
if(n<=4)printf("%d
",n);
else
{
int re=n%3;
int de=n/3;
if(re==1)
{
de--;
re=4;
}
if(re)f(re);
while(de--)f(3);
for(int i=cnt-1;i>=0;i--)
{
printf("%d",a[i]);
}
printf("
");
}
}
}
return 0;
}
Problem C: 试 制 品 Time Limit: 1 Sec Memory Limit: 128 MB Submit: 12 Solved: 6 [Submit][Status][Web Board] Description ZZ大学的Dr.Kong最近发现实验室的很多试制品都已经用完。由于项目经费有限,为了节省,Dr.Kong决定利用实验室现有的试制品来生成所缺的试制品。为此,Dr.Kong连续几天通宵达旦整理出一份研究资料并让研究生Bill去实验并统计能产生多少种所缺的试制品。
Bill从头到尾翻完所有的资料,发现资料上写满了一大堆的化学方程式,上面除了大小写英文字母、数字、加号、等号外,再也没有其他的符号了。其中,每个方程式都是A1+A2+……+Ap=B1+B2+……+Bq的形式, 表示试制品A1,A2,……和Ap反应,生成了试制品B1,B2,……,Bq。其中Ai和Bj都是一种单质或化合物的化学式(长度不超过10个字符),1≤p,q ≤ 20 。每个方程式的总长不超过100个字符。有些试制品的化学式可能在现代社会的化学元素周期表里找不到,这是由于化学反应过程中可能又有物理反应导致的结果。
Bill头疼了,从哪个实验开始呢?你能帮助他吗?
Input 第一行: N 表示Dr.Kong写的化学方程式个数 (1≤ N ≤ 400)
接下来有N行, 每一行是一个方程式。
再接下来的一行:M 表示已有多少种试制品。 (1≤ M ≤500)
接下来有M行,每一行是已有的一种试制品的化学式。
Output 第一行包含一个数T,表示可以产生多少种所缺的试制品。
在接下来的T行中,按ASCII码升序输出产生的试制品的化学式。
Sample Input 4 H2O+Na=NaOH+H2 Cl2+H2=HCl Fe+O2=Fe3O4 NaOH+HCl=H2O+NaCl 3 H2O Na Cl2 Sample Output 4 H2 HCl NaCl NaOH
这道题给我的启示就是,该暴力写就暴力写,不要总想着映射啊,优化啊,节省空间啊。 你先写出来个暴力的好不好。 一开始就想着优化,导致自己在编写的时候自己给自己找麻烦。 Orz
#include
using namespace std;
const int maxn=500;
int n,m;
map map1;
set set1;
int cnt=0;
bool vis[maxn];
class F
{
public:
set s1,s2;
};
F f[maxn];
string str;
set ans;
void init()
{
map1.clear();
for(int i=0;i!=maxn;i++)
{
f[i].s1.clear();
f[i].s2.clear();
}
set1.clear();
memset(vis,0,sizeof(vis));
ans.clear();
}
void out()
{
set::iterator it;
for(it=set1.begin();it!=set1.end();it++)
{
cout<<*it<<endl;
}
cout<<endl;
}
int main()
{
freopen("in.txt","r",stdin);
while(~scanf("%d",&n))
{
init();
cnt=1;
cin.get();
for(int i=0;i!=n;i++)
{
getline(cin,str);
string t="";
int j=0;
for(j=0;j!=str.size();j++)
{
if(str[j]=='=')break;
if(str[j]=='+')
{
f[i].s1.insert(t);
t="";
}
else
{
t+=str[j];
}
}
f[i].s1.insert(t);
j++;
t="";
for(;j!=str.size();j++)
{
if(str[j]=='+')
{
f[i].s2.insert(t);
t="";
}
else
{
t+=str[j];
}
}
f[i].s2.insert(t);
// set::iterator it;
// for(it=f[i].s1.begin();it!=f[i].s1.end();it++)
// {
// cout<<*it<<" ";
// }
// cout ";
// for(it=f[i].s2.begin();it!=f[i].s2.end();it++)
// {
// cout<<*it<<" ";
// }
// cout<<endl;
}
scanf("%d",&m);
cin.get();
for(int i=0;i!=m;i++)
{
getline(cin,str);
set1.insert(str);
}
bool flag=1;
while(flag)
{
flag=0;
for(int i=0;i!=n;i++)
{
if(vis[i])continue;
bool flag1=1;
set::iterator it;
for(it=f[i].s1.begin();it!=f[i].s1.end();it++)
{
if(set1.find(*it)==set1.end())
{
flag1=0;
break;
}
}
if(flag1==0)continue;
flag=1;
for(it=f[i].s2.begin();it!=f[i].s2.end();it++)
{
if(set1.find(*it)==set1.end())
{
ans.insert(*it);
set1.insert(*it);
}
}
vis[i]=1;
}
}
cout<<ans.size()<<endl;
set::iterator it;
for(it=ans.begin();it!=ans.end();it++)
{
cout<<*it<<endl;
}
}
return 0;
}
Problem D: 遥 控 器 Time Limit: 1 Sec Memory Limit: 128 MB Submit: 6 Solved: 2 [Submit][Status][Web Board] Description Dr.Kong 有一台高级电视机,这台电视机可以接受100个频道(从0到99编号)。电视的配套遥控器有13个按钮:
1 2 3 ↑
4 5 6 ↓
7 8 9
— 0
当按"↑"键时,当前频道编号会增加1(如果当前为99频道,则会切换到0频道)。如果按"↓"键,当前频道编号会减小1(如果当前为0频道,则会切换到99频道)。当要切换到09频道时,可以直接在遥控器上按相应的键。当要切换到1099频道时,可以先按"—"键,然后按2个与频道编号相对应的数字键(即先按与频道编号的十位数字相对应的键,然后按与个位数字相对应的键)。
由于遥控器长时间的使用和某些未知原因,遥控器上的某些键已经坏了,不能再起作用了。现在你的任务是,能否告诉Dr.Kong,如何用最少的按键次数来将频道从编号X切换到编号Y。
Input 第一行: N 表示有N组测试数据。 (1<=N<=5)
对每组测试数据有5行,前4行包含遥控器上每个按键的信息。0表示对应的键坏了,1表示对应的键可以使用。第5行包含2个整数,分别是X 和 Y (0 <= X <= 99; 0 <= Y <= 99)。
Output 对每组测试数据输出一行,即将频道从编号X切换到编号Y所需要的最小按键次数。如果不可能将频道从编号X 切换到编号Y,则输出-1.
Sample Input 2 0 0 1 1 1 1 1 1 1 1 1 1 1 23 52 1 1 1 0 1 1 1 0 1 0 1 0 1 23 52 Sample Output 4 -1
最小的步数嘛,然后考虑到电视台的总数又不多,所以广搜一波就好。
但是注意采用那个 - 功能键,来进行双数台的跳转的时候需要用三步,可能比单步功能键慢。 我们在使用单步键时,要对这个进行一下优化距离就好
#include
using namespace std;
int T;
bool on[13];
int x,y;
int dis[100];
void bfs()
{
memset(dis,0,sizeof(dis));
dis[x]=1;
queue q;
q.push(x);
while(q.size())
{
int p=q.front();
q.pop();
//°´Ò»¸öÊý×Ö¼ü½øÐÐÌøתµÄ·½·¨
//µ¥²½¹¦Äܼü
for(int i=0;i!=10;i++)
{
if(!on[i])continue;
if(!dis[i])
{
dis[i]=dis[p]+1;
q.push(i);
}
}
//µ¥²½¹¦Äܼü
if(on[10])
{
int nextx=p+1;
if(nextx>99)nextx-=100;
//Èç¹ûûÓзÃÎʹý£¬»òÕßʹÓõ¥²½¼ü±È֮ǰµÄÈý²½¼ü¿ì£¬ÄÇôÎÒÃÇÖØмÆËã
if(!dis[nextx]||dis[p]+1<dis[nextx])
{
dis[nextx]=dis[p]+1;
q.push(nextx);
}
}
//µ¥²½¹¦Äܼü
if(on[11])
{
int nextx=p-1;
if(nextx<0)nextx+=100;
//Èç¹ûûÓзÃÎʹý£¬»òÕßʹÓõ¥²½¼ü±È֮ǰµÄÈý²½¼ü¿ì£¬ÄÇôÎÒÃÇÖØмÆËã
if(!dis[nextx]||dis[p]+1<dis[nextx])
{
dis[nextx]=dis[p]+1;
q.push(nextx);
}
}
//Èý²½¹¦Äܼü
if(on[12])
{
//Èç¹ûÄÜʹÓÃÌøת¼ü£¬ÄÇôÎÒÃÇ¿ÉÒÔÌøתµ½Á½Î»ÊýµĄ̈£¬
//ö¾ÙËùÓпÉÄܵĄ̈£¬±Ï¾¹ÎÒÃÇÊÇbfs
//ö¾ÙʮλÊýµÄÊý×Ö
for(int i=0;i!=10;i++)
{
if(!on[i])continue;
//ö¾Ù¸öλÊý
for(int j=0;j!=10;j++)
{
if(!on[j])continue;
int nextx=i*10+j;
if(!dis[nextx])
{
//ÓпÉÄÜʹÓõ¥²½°´¼üÒª°´Á½Ï²ÅÄܵ½£¬µ«°´Èý²½¼üһϵ½ÁË£¬
//ÎÒÃÇÒªÔÚµ¥²½¼üÄÇÀï¶ÔÕâÖÖ²»´ÏÃ÷µÄÈý²½¼ü½øÐÐÓÅ»¯
dis[nextx]=dis[p]+3;
q.push(nextx);
}
}
}
}
}
}
int main()
{
freopen("in.txt","r",stdin);
while(~scanf("%d",&T))
{
while(T--)
{
int t;
for(int i=1;i<=3;i++)
{
scanf("%d",&t);
on[i]=t;
}
scanf("%d",&t);on[10]=t;
for(int i=4;i<=6;i++)
{
scanf("%d",&t);
on[i]=t;
}
scanf("%d",&t);on[11]=t;
for(int i=7;i<=9;i++)
{
scanf("%d",&t);
on[i]=t;
}
scanf("%d",&t);on[12]=t;
scanf("%d",&t);on[0]=t;
scanf("%d %d",&x,&y);
// for(int i=0;i!=13;i++)
// {
// cout<<on[i];
// }
// cout<<endl;
// cout<<x<<y<<endl;
bfs();
if(dis[y]==0)
{
printf("-1
");
}
else
{
printf("%d
",dis[y]-1);
}
}
}
return 0;
}
Problem E: 奇妙的图案 Time Limit: 1 Sec Memory Limit: 128 MB Submit: 0 Solved: 0 [Submit][Status][Web Board] Description 最近,Dr. Kong对几何图形发生了浓厚的兴趣。他发现在一个凸多边形里随意加上几个等半径的圆,再将圆涂成不同的颜色,就能构造出一幅美妙的图案。进而,Dr. Kong大发灵感,在此图案的基础上,又加入了几条连接凸多边形的两个不相邻顶点的直线,图形更加奇妙。
这时,Dr. Kong遇到了一个问题,他不想让加入的直线相互交叉,也不想让加入的直线穿过凸多边形里的任何一个圆,甚至不能与任何圆相切。
已经知道凸多边形的N个顶点的坐标,也知道了其中M个圆的圆心坐标和半径R。你能帮助Dr. Kong计算出可加上的满足所有条件的最多直线数吗?
Input 第1行: N M R 三个正整数
接下来有N行, 每一行为凸多边形一个坐标TXi TYi (i=1,…,N)
再接下来有M行,每一行为一个圆的圆心坐标PXj PYj (j=1,…,M)
Output 输出有一个整数, 表示可加上的最多直线数。
5≤ N ≤150 0≤ M ≤100 1≤ R ≤100,000 0≤ 所有坐标X,Y≤100,000
Sample Input 5 3 1 6 10 10 7 9 1 2 0 0 3 2 2 5 6 8 3 Sample Output 1
网上没搜到题解,个人感觉要涉及到分治的思想。 就是看看用一条边,把整个图形分成两半左边的最大值加右边的最大值,由于一个大块可能需要被求解很多次,所以我们采用记忆的方式来加速。但是。。。。,并不是太会写,也没有相关代码可以参考学习,那么我就暂时先不去磕这题了。
哦,还有样例的一个图,可以先放这里: 那个应该是话的不标准的原因,哈哈,我居然可以同时画两条不相交的线。。。
Problem F: Metric Matrice Time Limit: 1 Sec Memory Limit: 128 MB Submit: 8 Solved: 5 [Submit][Status][Web Board] Description nt j, determine if the distance matrix is “a metric” or not.
A distance matrix a[i][j] is a metric if and only if
1. a[i][i] = 0
2. a[i][j]> 0 if i != j
3. a[i][j] = a[j][i]
4. a[i][j] + a[j][k] >= a[i][k] i ¹ j ¹ k
Input The first line of input gives a single integer, 1 ≤ N ≤ 5, the number of test cases. Then follow, for each test case,
-
Line 1: One integer, N, the rows and number of columns, 2 <= N <= 30
-
Line 2…N+1: N lines, each with N space-separated integers
(-32000 <=each integer <= 32000).
Output Output for each test case , a single line with a single digit, which is the lowest digit of the possible facts on this list:
* 0: The matrix is a metric
* 1: The matrix is not a metric, it violates rule 1 above
* 2: The matrix is not a metric, it violates rule 2 above
* 3: The matrix is not a metric, it violates rule 3 above
* 4: The matrix is not a metric, it violates rule 4 above
Sample Input 2 4 0 1 2 3 1 0 1 2 2 1 0 1 3 2 1 0 2 0 3 2 0 Sample Output 0 3
嗯,是个模拟题,没啥好说的,我居然还wa了一发。。。
#include
using namespace std;
const int maxn=35;
int T,n;
int map1[maxn][maxn];
bool check1()
{
for(int i=0;i!=n;i++)
{
if(map1[i][i])return 0;
}
return 1;
}
bool check2()
{
for(int i=0;i!=n;i++)
{
for(int j=0;j!=n;j++)
{
if(i==j)continue;
if(map1[i][j]<=0)return 0;
}
}
return 1;
}
bool check3()
{
for(int i=0;i!=n;i++)
{
for(int j=0;j!=i;j++)
{
if(map1[i][j]!=map1[j][i])return 0;
}
}
return 1;
}
bool check4()
{
for(int i=0;i!=n;i++)
{
for(int j=0;j!=n;j++)
{
for(int k=0;k!=n;k++)
{
if(i==j||j==k||i==k)continue;
if(map1[i][j]+map1[j][k]<map1[i][k])return 0;
}
}
}
return 1;
}
int main()
{
freopen("in.txt","r",stdin);
while(~scanf("%d",&T))
{
while(T--)
{
scanf("%d",&n);
for(int i=0;i!=n;i++)
{
for(int j=0;j!=n;j++)
{
scanf("%d",&map1[i][j]);
}
}
if(!check1())
{
printf("1
");
}
else
if(!check2())
{
printf("2
");
}
else
if(!check3())
{
printf("3
");
}
else
if(!check4())
{
printf("4
");
}
else
{
printf("0
");
}
}
}
return 0;
}