小w是云南中医学院的同学,有一天他看到了学校的百度百科介绍:
截止到2014年5月,云南中医学院图书馆纸本藏书74.8457万册,纸质期刊388种,馆藏线装古籍图书1.8万册,电子资源总量35TB,拥有中、外文数据库25个,电子图书29.5万册(镜像)、包库130万册。古籍线装图书1.8万余册,有39种列为本馆珍善本,如《彻滕八编》、《赵氏医贯》等明清版本、台湾文渊阁版本《四库全书》,按《全国古籍善本书总目》分类表(即:经·史·子·集四部分类)部编列、上架、供读者使用。
显然学校图书馆的占地面积非常大,于是他开始想象.....如果他有一个跟图书馆一样大的游泳池?!
如果有一个那么大的游泳池,他就可以邀请女神一起去游泳...
如果有一个那么大的游泳池,他还可以划开一半出租,收取门票费赚钱...这样等赚了一些钱之后,就招一些游泳教练来,然后对外招生,招收学生继续赚更多的钱!
如果有一个那么大的游泳池,他还能把泳池里的水全部放光...开一个吕子乔心目中最大最棒的泳池派对!
.......
等有了更多的钱,就可以在第一个泳池旁边再建一个一样大的泳池......
小w一边流口水一边想自己的未来,一想到女神看到自己事业有成,靠一个游泳池白手起家发家致富,对自己投怀送抱,高兴的根本合不拢嘴。
这时候旁边的小q作为小w的室友,随口提了一句:“这么大的泳池,你怎么换水?”
显然小w是个有原则的人,他不会让自己的泳池像不法商家一样不换水,用不干净的水给别人使用或者给自己使用。
小w百度了之后发现...淘宝里有一家店卖一种一次性抽水机,这种一次性抽水机很神奇,它有两个按钮:
1.如果泳池里的水(立方米)是3的倍数,那么可以按第一个按钮让它抽走泳池里三分之二的水
2.如果泳池里的水(立方米)是2的倍数,那么可以按第二个按钮让它抽走泳池里二分之一的水
小w虽然是个有原则的人,但是作为一个商人,他需要节省钱...而且他现在有两个泳池....但是显然这种抽水机不能把水抽光,水越少,性价比就越低。
但是两个泳池建在一起,如果两个泳池的水面不一样高,那么小w会很不开心,所以他想用这种抽水机,把两个泳池里的水抽成一样多。然后再考虑别的....当然在保证能把两个泳池里的水抽成一样多的情况下..他希望花的钱最少...
(不管了!好看最重要,好看才能吸引顾客啊!先好看!再考虑怎么换水吧)
多组测试数据,给出A,B表示两个泳池当前的水量(立方米)
(1<=A,B<=10^9)
每组测试数据输出一个整数表示至少需要买多少个一次性抽水机,若买多少个都不能让泳池的水相等,则输出"-1"
也是一道读完题目模拟一下就可以解决的问题,因为对总量a或者b只能进行/2或者/3的操作,想要使得a==b,那么如果存在方案,那么最终a和b会变成gcd(a,b),那么只要只要对剩下的a/gcd(a,b)和b/gcd(a,b)进行/2和/3操作判断是否能全部消掉
#include
int gcd(int x,int y)
{
return y==0?x:gcd(y,x%y);
}
int main()
{
int a,b;
while(~scanf("%d%d",&a,&b))
{
if(a==b)
{
printf("0\n");
continue;
}
int t=gcd(a,b);
a/=t;b/=t;
int ans=0;
while(a%2==0){a/=2;ans++;}
while(a%3==0){a/=3;ans++;}
while(b%2==0){b/=2;ans++;}
while(b%3==0){b/=3;ans++;}
if(a!=b)
printf("-1\n");
else
printf("%d\n",ans);
}
return 0;
}
Problem C: 调酒壶里的酸奶
Time Limit: 1 Sec
Memory Limit: 128 MB
Submit: 54
Solved: 12
[ Submit][ Status][ Web Board]
Description
最近小w学了一手调酒的技巧,这么帅的操作,说不定能靠这个俘获女神的芳心,为了在女神面前露一手,他想在学校里建一个"pub",但是显然学校不可能让他真的建一个"pub",那么他退而求次,想建一个"Yogurt shop",不能用酒,那用酸奶也行啊!
今天女神终于来光顾小w的酸奶店了!兴奋的小w拿出自己准备已久每天都仔细擦干净的装备——调酒壶、果汁机、隔冰器和计量杯、砧板、小刀....准备露一手给女神看看
但是女神却没有那么多耐心,女神只是觉得,自己买一瓶大酸奶喝不完,小瓶酸奶不够喝,所以在小w的酸奶店,说不定她可以想买多少就买多少。
于是女神告诉了小w她想要多少体积的酸奶,而小w却依旧想秀一下自己的操作,于是他决定用仅有的两个调酒壶为女神倒出女神想要的酸奶....
小w的两个调酒壶体积是不同的(一开始都是空的),小w每次可以选择一个调酒壶倒入另一个调酒壶(若A倒入B,A倒完或B倒满则停止),或者选择一个调酒壶倒光,或者选择一个调酒壶去接满酸奶.....
满心失望的小w想找一朵花,一瓣一瓣的撕下来,问问花朵女神到底喜不喜欢他...虽然这个答案是显而易见的,但是他还是想找一朵花...然而找花未果,反正花瓣不是偶数就是奇数,那他索性就用自己的操作次数作为花瓣个数吧!(找不到花我还不能脑补一朵吗...)
但是小w已经没有心情去想答案了...那么你能告诉他,需要多少步操作才能倒出女神想要的酸奶吗?
Input
输入包含多组数据,每行三个正整数a,b,c分别表示两个调酒壶的容量以及女神想要的酸奶体积,a,b的范围都在[0,100],c<=max(a,b)
Output
一行包含一个整数表示完成要求的最少操作次数,若达不到则输出"impossible"(没有双引号)
Sample Input
10 15 11
6 5 4
Sample Output
impossible
4
【分析】
说实话就是个原题...不过这种一眼就看得出来是记忆化搜索的搜索也没什么原题这种说法了...
对每个状态都有六种情况:
1.把A倒满
2.把B倒满
3.把A倒光
4.把B倒光
5.把A倒进B
6.把B倒进A
六个情况直接搜索就可以了...当然dfs是会超时的,需要用记忆化搜索
【代码】
#include
#include
#include
#include
#include
using namespace std;
int A,B,C;
int vis[200][200],dis[200][200];
struct xx{
int a,b;
xx(int a,int b):a(a),b(b){}
};
int bfs()
{
queue q;
memset(vis,0,sizeof(vis));
memset(dis,0,sizeof(dis));
dis[0][0]=0;
vis[0][0]=1;
q.push(xx(0,0));
while(!q.empty())
{
xx x=q.front();
q.pop();
for(int i=1;i<=6;i++)
{
int X,Y;
if(i==1){X=A;Y=x.b;}
if(i==2){X=x.a; Y=B;}
if(i==3){X=0; Y=x.b;}
if(i==4){X=x.a; Y=0;}
if(i==5){X=x.a+x.b>=B?x.a+x.b-B:0;Y=x.a+x.b>=B?B:x.a+x.b;}
if(i==6){X=x.a+x.b>=A?A:x.a+x.b;Y=x.a+x.b>=A?x.a+x.b-A:0;}
if(!vis[X][Y])
{
vis[X][Y]=1;
dis[X][Y]=dis[x.a][x.b]+1;
if(X==C||Y==C) return dis[X][Y];
q.push(xx(X,Y));
}
}
}
return -1;
}
int main()
{
while (~scanf("%d%d%d",&A,&B,&C))
{
int ans=bfs();
if (ans!=-1) printf("%d\n",ans);
else printf("impossible\n");
}
return 0;
}
Problem D: 过分的谜题
Time Limit: 1 Sec
Memory Limit: 128 MB
Submit: 58
Solved: 30
[ Submit][ Status][ Web Board]
Description
2060年是云南中医学院的百年校庆,于是学生会的同学们搞了一个连续猜谜活动:共有10个谜题,现在告诉所有人第一个谜题,每个谜题的答案就是下一个谜题的线索....成功破解最后一个谜题后,答案就是指向奖励的线索
在所有同学们的努力下,全校同学们获得了最后一个谜题,这个谜题有几十张纸,上面全是密密麻麻的数字以及'.'
第一页内容如下:
1,2,3,4,5,6
4,1,5,2,6,3
2,4,6,1,3,5
1,2,3,4,5,6
———3
1,2,3,4....32
.............
.............
———10
有细心的同学发现,这是对一组1-2n的序列进行如下移动:每次将前n个数字取出,按顺序依次插入到位于n+1,n+2...2n的数字后面,最后的数字表示多少次移动后会变回原来的序列
第二页内容如下:
1,2,3,4....64
.............
.............
———?
1,2,3,4....140
.............
.............
———?
同学们发现,越往后翻,这个序列的长度就越长,前面十几二十个数字的序列同学们还可以一步一步模拟做出来,但是到后来几千甚至上万的长度,就没有办法计算了,甚至中间一步做错,就步步都错。
这个谜题真是太过分了!但是奖励就在眼前,只要计算出所有答案,所有答案就是指引同学们获得奖励的线索,那么现在问题来了,同学们除了发现上面的n=最后那个数字/2之外,没有办法给你任何帮助,而作为一个计算机科学与技术专业的大佬,你自然就成为了同学们心目中拯救他们的英雄,所以你能不能写一个程序,当你知道n是多少的时候,可以直接得出答案呢?
Input
多组测试数据.每组数据的第一行包含一个正整数n(1<= n<=10000).
Output
每组数据输出一行整数表示最少需要经过几次移动能变回原序列,若不能,则输出"-1"
Sample Input
3
16
Sample Output
3
10
【分析】
稍微模拟一下就会发现,每个数的位置变化就是当前位置编号*2%(n+1)
那么题目里只问多少次会变回原来的序列,那显然只要挑一个数盯着看它什么时候回去,那其他的数字必然也已经回去
对于-1这个情况...因为题目给定的保证是2n,为偶数,那就不可能会有-1的情况了
【代码】
#include
#include
using namespace std;
int main()
{
int n;
while (~scanf("%d",&n))
{
int ans=1;
n*=2;
int x=2;
while (x!=1)
{
ans++;
x=(x*2)%(n+1);
}
printf("%d\n",ans);
}
return 0;
}
Problem E: 小C的数学问题
Time Limit: 1 Sec
Memory Limit: 128 MB
Submit: 50
Solved: 13
[ Submit][ Status][ Web Board]
Description
小C是个云南中医学院的大一新生,在某个星期二,他的高数老师扔给了他一个问题。
让他在1天的时间内给出答案。
但是小C不会这问题,现在他来请教你。
请你帮他解决这个问题。
有n个数,每个数有权值。
数学老师定义了区间价值为区间和乘上区间内的最小值。
现在要你找出有最大区间价值的区间是什么,并输出区间价值。
Input
每个输入文件只包含单组数据。
第一行一个整数n。(1 <= n <= 100000)
第二行n个整数a_1,a_2,...,a_n。(0 <= a_i <= 1000000)
Output
第一行输出一个整数,表示最大的区间价值。
第二行输出两个整数,表示区间的起点和终点。
保证答案唯一。
Sample Input
6
10 1 9 4 5 9
Sample Output
108
3 6
【分析】
原意呢是个单调栈的应用,应该是本场比赛最难题了。
但是其实只要知道一点,对于每个ai,它所影响的区间其实就是向前遍历到比它小的数后一位,向后遍历到比它小的数前一位,那么这个区间就是这个ai所影响的区间,这样考虑的话复杂度就会比O(n^2)快,然后在这个思路的基础上,用set啊链表啊维护一下当前位置往前到哪里往后到哪里,只要能把求区间的步骤优化掉,随便怎么做可以
【代码】
set维护
#include
using namespace std;
typedef long long ll;
const ll maxn=100010;
struct node
{
ll x,id;
friend bool operator<(const node&a,const node&b)
{
return a.xs1,s2;
ll add[maxn];
int main()
{
ll n;
while(scanf("%lld",&n)==1)
{
add[0]=0;
s1.clear();
s2.clear();
set::iterator it;
for(ll i=1;i<=n;i++)
{
a[i].id=i;
scanf("%lld",&a[i].x);
add[i]=add[i-1]+a[i].x;
}
ll ans=-1,l,r;
s1.insert(n+1);
s2.insert(n+1);
sort(a+1,a+n+1);
for(ll i=1;i<=n;i++)
{
ll L=i,R=i;
while(a[R+1].x==a[L].x&&R<=n) R++;
for(ll j=L;j<=R;j++)
{
it=s2.lower_bound(n+1-a[j].id);
ll tl=n+1-*it;
it=s1.lower_bound(a[j].id);
ll tr=*it;
ll tmp=(add[tr-1]-add[tl])*a[j].x;
if(tmp>ans)
{
ans=tmp;
l=tl+1,r=tr-1;
}
}
for(ll j=L;j<=R;j++)
{
s1.insert(a[j].id);
s2.insert(n+1-a[j].id);
}
i=R;
}
printf("%lld\n%lld %lld\n",ans,l,r);
}
return 0;
}
单调栈
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ALL(v) (v).begin(),(v).end()
#define cl(a,b) memset(a,b,sizeof(a))
#define clr clear()
typedef long long LL;
const int maxn = 100000 + 10;
LL sum[maxn];
struct Node{
int v,l,r;
}a[maxn],b[maxn];
int main()
{
#ifdef local
freopen("test8.in","r",stdin);
freopen("test8.out","w",stdout);
clock_t start_time=clock();
#endif
int n;
while(~scanf("%d",&n)) {
assert(1 <= n <= 100000);
for (int i = 1; i <= n; i++) {
scanf("%d",&a[i].v);a[i].l = a[i].r = i;
assert(0 <= a[i].v && a[i].v <= 1000000);
sum[i] = sum[i-1] + a[i].v;
}
stackq;
Node t;
int ind = 0,L,R;
for (int i = 1; i <= n; i++) {
if(q.empty()) {
q.push(a[i]);
}
else {
while (!q.empty() && q.top().v >= a[i].v) {
t = q.top();q.pop();
a[i].l = t.l;
b[ind++] = t;
if(!q.empty())q.top().r = t.r;
}
q.push(a[i]);
}
}
Node tmp = q.top();q.pop();
b[ind++] = tmp;
while(!q.empty()) {
t = q.top();q.pop();
t.r = tmp.r;
b[ind++] = t;
}
LL ans = -1;
for (int i = 0; i < ind; i++) {
LL s = b[i].v * (sum[b[i].r] - sum[b[i].l-1]);
if(ans < s) {
ans = s;
L = b[i].l;
R = b[i].r;
}
}
printf("%lld\n%d %d\n",ans,L,R);
}
#ifdef local
clock_t end_time=clock();
double run_time = (double)(end_time - start_time) / CLOCKS_PER_SEC * 1000;
cerr<
Problem F: fps游戏
Time Limit: 1 Sec
Memory Limit: 128 MB
Submit: 150
Solved: 27
[ Submit][ Status][ Web Board]
Description
fps游戏是第一人称射击游戏。这类游戏有一个很重要的技巧也是基本功之一的,是压枪。
为了模拟真实环境,在游戏里你每开一枪,枪口都会往上和左右浮动。
如果你想使枪口在某个范围内,为了提高精准度,你就必须压枪。
而且每把枪的后坐力不同和有效打击距离不同,就需要对每把枪都很熟悉,能很快的计算出在多远距离外开枪枪口会往上和左右浮动多少。
现在只考虑枪的垂直浮动。
假设在d米外有一个靶子,初始枪口正对靶心的圆心,靶心是个半径为r米的圆,现在你要射击c次。(你可以把枪看成一个点)。
为了省力,要使压枪次数最少。
只有当在靶上的射击位置在靶心之外时才需要压枪。
每次压枪,枪口都会回到上次的射击位置。
每次开枪最多只能压一次枪,不能连续压枪。
Input
每个输入文件只包含一组数据。
包含3个正整数d,r,c和1个实数a(d,r,c意义如上文所述,a是每次开枪,枪口向上浮动的角度)。
(1 <= d,r <= 100,0 <= c <= 1000000,0 <= a < 90)
Output
Sample Input
10 1 10 3
Sample Output
8
【分析】
考验高中数学水平的时候到了....只要算算到哪一枪开始会脱靶,那么后面的统统都需要压枪...直接计算就可以
【代码】
#include
using namespace std;
const double pi=acos(-1);
int main()
{
double a;
int d,r,c;
scanf("%d%d%d%lf",&d,&r,&c,&a);
double sig=atan(1.0*r/d);
sig=sig/pi*180;
int t=sig/a+1;
printf("%d\n",max(0,c-t));
return 0;
}
Problem G: 闪闪发光
Time Limit: 1 Sec
Memory Limit: 128 MB
Submit: 49
Solved: 16
[ Submit][ Status][ Web Board]
Description
一所位于云南昆明的中医药本科院校--云南中医学院。
因为报考某专业的人数骤减,正面临着停招的危机。
其中有九名少女想到一条妙计——成为偶像,
只要她们成为偶像,学校的名气便会增加,而报考的人数亦会上升。
就这样,九位个性鲜明的少女决定一起努力成为偶像。
希望可以凭借偶像的名气增加生源来挽救自己所喜爱的专业,让自己的学校闪闪发光。
她们为了成为偶像,第一步对于她们来说是减肥!
这里有n个重物,第i个重物的重量是2^{w_i}。她们每天任务要完成的重量是n个重物的重量和。
每次举重的重量和必须是2的幂,重物数量不要求。
但是为了方便,要使举重的次数最少。
Input
多组数据。
每组数据第一行一个整数n。(1 <= n <= 10^6)
第二行有n个整数w_1,w_2,...,w_n。(0 <= w_i <= 1000000)
Output
Sample Input
5
1 1 2 3 3
Sample Output
2
HINT
【分析】
Problem H: 流连人间的苏苏
Time Limit: 1 Sec
Memory Limit: 128 MB
Submit: 93
Solved: 30
[ Submit][ Status][ Web Board]
Description
苏苏在做红尘仙的任务时,发现坐落于风景秀丽、四季如春的昆明市的云南中医学院。
没过多久,苏苏就喜欢上了这个学校。以致于苏苏忘了回涂山的时间,现在她只剩下d天的时间待在云南中医学院。由于时间紧迫,苏苏想方设法为建设更好的云南中医学院。
假设学校里某条街道有n个房子。
每天选择两个门牌号l、r,给这两个门牌号之间的所有房子的门前都栽一棵树,已经有树的不需要再种。
苏苏想知道在某天,有哪些房子前有树。
Input
每个输入文件只有一组数据
第一行包含n,d。(1 <= n,d <= 1000)
接下来d行,每行包含两个整数l,r(1 <= l <= r <= n)
Output
输出d行。
每行输出门牌号的区间。每个区间以逗号分隔。
具体看样例。
Sample Input
10 4
1 3
2 4
5 6
8 10
Sample Output
[1,3]
[1,4]
[1,6]
[1,6],[8,10]
【分析】
按题意直接做就行,无论优不优化..反正数据非常小
【代码】
#include
using namespace std;
int main()
{
int n,d,v[1010];
scanf("%d%d",&n,&d);
memset(v,0,sizeof(v));
while(d--)
{
int l,r,t=0;
scanf("%d%d",&l,&r);
for(int i=l;i<=r;i++) v[i]=1;
for(int i=1;i<=n;i++)
{
if(v[i])
{
if(t) printf(","); t=1;
printf("[%d,",i);
while(v[i]&&i<=n) i++;
printf("%d]",i-1);
}
}
printf("\n");
}
return 0;
}
Problem I: 奔赴云南
Time Limit: 1 Sec
Memory Limit: 128 MB
Submit: 121
Solved: 36
[ Submit][ Status][ Web Board]
Description
第二届全国中医药程序设计大赛在云南中医学院举行,全国各中医药院校从全国各地奔赴云南。
每个人的车票或机票上都会有如下信息:
地名 出发时间 到达时间
- 地名:长度不超过20
- 出发时间: 格式hhmm
- 到达时间: 格式hhmm
(0 <= hh <= 23,0 <= mm <= 59)
但是他们想知道在路上所花费的时间总共是多少。
现在请你编写程序帮助他们计算时间。
Input
多组数据
每组数据有一个字符串s和两个整数Time1,Time2,分别表示地名,出发时间,到达时间。
保证 到达时间 >= 出发时间
Output
Sample Input
Hangzhou 1245 1723
Sample Output
Hangzhou to Kunming: 04:38
【分析】
签到题之一,把四位数时间换算成分钟,做完减法再换算回时间即可
【代码】
#include
int main()
{
char s[1000];
int time1,time2;
while (~scanf("%s%d%d",s,&time1,&time2))
{
int ans = time2 / 100 * 60 + time2 % 100 - time1 / 100 * 60 - time1 % 100;
printf("%s to Kunming: %02d:%02d\n",s,ans/60,ans%60);
}
return 0;
}
Problem J: TCMPC进阶之路
Time Limit: 1 Sec
Memory Limit: 128 MB
Submit: 47
Solved: 42
[ Submit][ Status][ Web Board]
Description
小w是云南中医学院计算机专业的一名学生,最近决心开始好好学习(当然是因为太菜被女神嫌弃了..)
作为一个超级菜的菜鸟,进步的最好方式就是奋发图强努力刷题!于是小w开始在ZCMUOJ中做题。ZCMUOJ新开了一个叫的专题,引进了一个新模式——积分系统,积分越多,账号称号就越高级:
[0-50]:菜鸟
(50-500]:入门
(500-2000]:黑铁级入门选手
(2000-8000]:青铜级入门选手
(8000-20000]:白银级入门选手
(20000-80000]:黄金级入门选手
(80000-200000]:钻石级入门选手
(200000-500000]:专业级入门选手
(500000-1000000]:TCMPC热身赛选手
(1000000-2000000]:TCMPC正赛选手
(2000000-5000000]:TCMPC铜牌选手
.........
当然,每道题目都有它相应的积分,ID为1的题目AC后会获得1分,ID为2的题目AC后获得2分...ID为i的题目AC后会获得i分,那么现在小w为了成为女神心目中的大神,决定从第一题开始做,绝不跳过任何题目,严格按顺序往下做。
那么现在小w已经做到第n题了,但是积分系统却没有显示个人积分,所以他想知道他现在的积分是多少,以便计算还需要多少题才能进阶,以此给自己动力,你能帮他吗?
Input
多组数据,第一行输入一个整数T(1≤T≤10000)表示数据组数
以下T行,每行输入一个正整数n(1≤n≤10000)表示小w当前做到第n题(第n题也已AC),且题目编号是有序的。
Output
Sample Input
2
5
10
Sample Output
15
55
【分析】
签到题之二,1到n求和...全场AC题
【代码】
#include
typedef long long LL;
int main()
{
int T;scanf("%d",&T);
while(T--) {
LL n;scanf("%lld",&n);
LL ans = (1 + n) * n / 2;
printf("%lld\n",ans);
}
return 0;
}