HHTC_学校集训编程题目(11)(组队赛_1)
简简单单记录一下几个题目,类似于签到题就不记录了~
B - Problem B. Memory Banks
We have purchased 60 different types of memory banks, typed as 0 to 59, A bank of type i has 2^i memory capacity. We have Xi memory banks of type i.
We also have n workstations numbered from 1 to n. The ith workstation needs exactly (no more and no less) Wi memory capacity to work.
Each workstation can use unlimited amount of memory banks, Total memory capacity of this workstation is the sum of capacity of all memory banks it used.
We need to make all workstations work and calculate the total capacity of unused memory banks, can you help us?
Input
Input is given from Standard Input in the following format:
X0 … X59
n
W1 … Wn
Constraints
0 ≤ Xi ≤ 2^60
1 ≤ n ≤ 100000
0 ≤ Wi ≤ 2^60
All of them are integers.
Output
Print one line denotes the answer.
If it is possible to make all workstations work, output a single number represents the total capacity of unused memory banks. It maybe very large, you should modulo 1000000007(10^9 + 7)
Otherwise output -1
Sample Input
4 2 2 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0
3
10 8 16
2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0
4
2 4 8 1
Sample Output
6
-1
题目意思如果能看懂的话那么也就不难了,就是一道模拟题目
一共有60个箱子,每个箱子有2^i个存储空间,ai表示有多少个箱子
然后给出要储存的东西需要的空间,求放完之后还剩多少
比如说样例:4 2 2 3
表示有4个1的箱子,2个2的箱子,2个4的箱子,3个8的箱子
要存储10 8 16
那么三个8的都用完,用2个4的,一个2的就刚刚好存完
还剩下,1*4+1*2=6
直接模拟,求方的时候需要快速幂的算法,还有要用 long long
AC代码:
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <map>
#include <set>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
#define mod 1000000007
typedef long long ll;
long long a[65],b[65],c[100005];
int n;
ll qa(ll a,ll b)
{
ll ans=0;
while(b)
{
if(b&1)
ans=(ans+a)%mod;
a=(a+a)%mod;
b>>=1;
}
return ans;
}
int main()
{
while(scanf("%lld",&a[0]) != EOF)
{
b[0] = 1;
bool flag = true;
for(int i=1; i<60; i++)
scanf("%lld",&a[i]),b[i] = 1ll<<i;
scanf("%d",&n);
for(int i=0; i<n; i++)
scanf("%lld",&c[i]);
sort(c,c+n,greater<long long>());
for(int i=0; i<n && flag; i++)
{
ll tmp = c[i];
for(int j=59; j>=0; j--)
{
if(tmp >= b[j])
{
ll num = tmp / b[j];
tmp = tmp % b[j];
if(a[j] >= num)
a[j] -= num,num = 0;
else
{
num -= a[j];
a[j] = 0;
}
tmp += num * b[j];
}
if(j == 0 && tmp)
flag = false;
}
}
ll ans = 0;
if(!flag)
printf("-1\n");
else
{
for(int i=0; i<60; i++)
if(a[i])
ans = (ans+qa(a[i],b[i]))%mod;
printf("%lld\n",ans);
}
}
return 0;
}
A - 小妖的下属
话说上回涂山小八成功解出真假小妖的难题,东方平平觉得很不开心,仿佛受到了嘲笑。于是他又造了一批假的小妖,气鼓鼓的找到了小八。
平平:“哼,我造的这批小妖ID号也有特殊属性。简单来说,一个小妖所领导的小妖个数就是它的ID号可以分解的方式数,所谓分解,就是把n分解成若干个连续正整数之和。如ID=15的小妖,下属有3人,因为它有(1,2,3,4,5),(4,5,6),(7,8)共3种分解方式。现在我想问你,每个小妖的下属个数是多少,赌上我刚买的一打妖馨斋“一品五彩棒”棒棒糖。”
如果你能帮小八解出来的话,小八会把一品五彩棒分给你哦~
Input
输入数据有多组,每组输入一个整数n(1≤n≤109),表示小妖的ID数字。
Output
对于每组数据,输出这个小妖的下属个数,每组输出占一行。
Sample Input
3
15
2788
Sample Output
1
3
3
题目意思应该都能懂,就不解释了,求连续序列的和
这里暴力肯定是不行的,所以转变一种方法~
利用等差数列求和公式,已知d=1,我们只需要枚举有多少项就可以了
然后求出有几个a1,
公式2*a1*n + (n-1)*n = 2* num,当a1能够为整数时,那么就是找到了一种
可以得知项数最大就是sqrt(num*2)
AC代码:
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <map>
#include <set>
#include <queue>
#include <vector>
#include <algorithm>
#include <math.h>
using namespace std;
void divide(int num)
{
int i,j,a;
int sum = 0;
for(i=2; i<=sqrt(num*2); ++i)
{
if((2*num - i*(i-1)) % (2*i) == 0){
a = (2*num - i*(i-1)) / (2*i);
sum++;
}
}
printf("%d\n",sum);
}
int main(){
int n;
while(scanf("%d",&n) != EOF){
divide(n);
}
return 0;
}
C - 巴啦啦能量
话说上回涂山小八进入“时空之门”,却不是回到现实世界,而是一间方正小屋。随着时空之门缓缓关上,小八才看清墙上排着很多奇怪的字符。正奇怪着,小屋内响起了说话声。
“你现在本应已回到现实世界,但你来的时间太久,能量已经用光,无法直接通过时空之门,所以才会来到此地。唯今之计只有获得巴啦啦能量,否则你依然会被永远留在此地。”
“如何获得巴啦啦能量?”
“看见墙上的巴啦啦密文了吗?我现在给你一个能量之匙,从巴啦啦密文中找出巴啦啦能量串即可获得巴啦啦能量。巴啦啦能量串是所有包含能量之匙的最小串,切记,若找到多个符合要求的巴啦啦能量串,不可贪多,只需带走第一个,否则前功尽弃。”
Input
输入数据有多组,每组数据输入第一行输入字符串巴啦啦密文S,第二行输入字符串能量之匙T,S长度lens(1≤lens≤105 ),T长度lent(1≤lent≤105 )(输入不包含空格),输入字符区分大小写。
Output
对于每组输入数据,输出找到的巴啦啦能量串,每组输出占一行。如果找不到巴啦啦能量串,输出一个空行。
Sample Input
ADOBECODEBANC
ABC
ABCDA
BD
Sample Output
BANC
BCD
这个题尺取法去找字符串,找最长的,这个题其实是队友写的,啊哈哈哈哈
AC代码:
#include <cstdio>
#include <cstring>
#include <cctype>
#include <string>
#include <set>
#include <iostream>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
using namespace std;
const int N=1e5+20;
char s[N],t[N];
int vis[200];//标记出现的次数
int sear[200];//标记是否出现过
int main()
{
while(~scanf("%s%s",s,t))
{
mem(vis,0);
mem(sear,0);
int tlen=strlen(t);
int slen=strlen(s);
for(int i=0; i<tlen; i++)
{
vis[t[i]]++;
sear[t[i]]=1;
}
int cnt=0,l=0,minl=0,minn=slen+1;
for(int r=0; r<slen; r++)
if(sear[s[r]])
{
if(--vis[s[r]]>=0)
cnt++;
while(cnt==tlen)
{
if(r-l+1<minn)
minl=l,minn=r-l+1;
if(sear[s[l]])
if(++vis[s[l]]>0)
cnt--;
l++;
}
}
if(minn>slen) printf("\n");
else
{
for(int i=minl; i<minl+minn; i++)
printf("%c",s[i]);
printf("\n");
}
}
return 0;
}
E - 貂蝉的试炼
公元2017年11月19日,涂山小八正在专注的和小伙伴五黑,突然一道白光,回过神来,小八已经站在一个陌生的地方,红爸爸、蓝爸爸、暴君、主宰…随着耳边响起“欢迎来到王者农药”,对面走来熟悉的貂蝉小姐姐,小八恍然明白自己是站在王者农药的战场上。
貂蝉:“我知道你在疑惑什么,现在你可以选择接受或不接受我的试炼,如果你接受并通过了,我可以回答你的所有疑问,并且送你回去。相反,你将继续留在这等待。”
小八:“……接受(ノ`Д)ノ另外,你是在cosplay吗?”
貂蝉:“不是(ノ`Д)ノ,这是一场关于力量和智慧的考验。决斗开始时,我将向你抛出n块魔法水晶。魔法水晶具有跟踪作用,除非你破解上面的魔法,否则一定会被攻击。如何破解?每块魔法水晶上有个神秘攻击值,是古代花丸幼稚王国消失已久的罗马数字,只要你快速转换成阿拉伯数字并大声喊三遍,水晶球就会失效。”
貂蝉:“我看你骨骼清奇,是开黑界的奇才,那就给你几点提示吧。
1、 罗马数字基本字符: I、V、X、L、C、D、M,分别表述阿拉伯数字1、5、10、50、100、500、1000。
2、重复数次:一个罗马数字重复几次,就表示这个数的几倍。
3、右加左减:
(1)在较大的罗马数字的右边记上较小的罗马数字,表示大数字加小数字。
(2)在较大的罗马数字的左边记上较小的罗马数字,表示大数字减小数字。
(3)左减的数字有限制,仅限于I、X、C。比如45不可以写成VL,只能是XLV。但是,左减时不可跨越一个位值。比如,99不可以用IC(100-1)表示,而是用XCIX([100-10]+[10-1])表示。(等同于阿拉伯数字每位数字分别表示。)
(4)左减数字必须为一位,比如8写成VIII,而非IIX。
(5)右加数字不可连续超过三位,比如14写成XIV,而非XIIII。
4、数码限制:同一数码最多只能连续出现三次,如40不可表示为XXXX,而要表示为XL。
以上为阿拉伯数字转罗马数字的规则,而你需要破解对应罗马数字的阿拉伯数字是多少。”
小八:“不懂。”
貂蝉:“看样例(ノ`Д)ノ”
作为小八队友的你,快点帮他回到现实世界,然后愉快的开黑吧。
Input
输入数据有多组,每组数据输入一个罗马数字n,(1≤n≤3999)。
Output
对于每组输入数据,输出罗马数字对应的阿拉伯数字,每组输出占一行。
Sample Input
VIII
XIX
XXXIX
XXI
XLI
Sample Output
8
19
39
21
41
一开始以为贼jb难,后来听了别人的讲解,好像不难的亚子
就是按照条件来进行判断就好了!!!!
AC代码:
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <map>
#include <set>
#include <queue>
#include <vector>
#include <algorithm>
#include <math.h>
using namespace std;
int main()
{
string s;
while(cin>>s)
{
int ans=0;
for(int i=0;s[i]!=0;i++)
{
if(s[i]=='M')
{
ans+=1000;
}
if((s[i+1]=='D'||s[i+1]=='M')&&s[i]=='C')
{
ans-=100;
}
else if(s[i]=='C')
{
ans+=100;
}
if(s[i]=='D')
{
ans+=500;
}
if(s[i]=='L')
{
ans+=50;
}
if((s[i+1]=='L'||s[i+1]=='C')&&s[i]=='X')
{
ans-=10;
}
else if(s[i]=='X')
{
ans+=10;
}
if(s[i]=='V')
{
ans+=5;
}
if((s[i+1]=='X'||s[i+1]=='V')&&s[i]=='I')
ans-=1;
else if(s[i]=='I')
ans+=1;
}
printf("%d\n",ans);
}
return 0;
}
F - 一品五彩棒
公元2017年11月19日,王权熊熊和东方平平因为妖馨斋出品的“一品五彩棒”棒棒糖大打出手。王权熊熊祭出神剑王权剑,东方平平不甘示弱,反手就拿出一打洋葱擦眼睛,想要放出大招——虚空之泪。
大战开始,打的天昏地暗,昏天黑地,飞沙走石,极其恐怖。
虚空之泪,只有具备强大法力且至情至性之人才能产生,世间最为坚硬,且可以通过切割空间达到瞬时缩短距离。
虚空之泪的形成需要三滴完美契合的普通泪滴。现有n滴普通泪滴,每滴泪滴具有坚硬属性,只有三滴普通泪滴的坚硬属性之和为0时,表示三滴泪滴完美契合,可以合成虚空之泪。问,n滴普通泪滴中,有多少组可以合成虚空之泪的普通泪滴?要求按照字典序输出它们的坚硬属性值。
Input
输入数据有多组,每组第一行输入一个整数n (1 ≤ n ≤ 3000),表示当前普通泪滴的数目。接下来输入n个整数ai(-106 ≤ ai ≤ 106),表示n滴泪滴的坚硬属性值。
Output
对于每组输入数据,找出所有可以合成虚空之泪的普通泪滴组合,按照提示里的顺序输出它们的坚硬属性值,相同的组合只输出一次,每种组合占一行。若不存在这种组合,不输出。每种组合输出到一行,两个数之间用空格隔开,行末不包含空格。
Sample Input
6
-1 0 1 2 -1 4
3
-1 -1 2
Sample Output
-1 -1 2
-1 0 1
-1 -1 2
Hint
输出顺序:不同组合之间按照第一个数字大小从小到大,若第一个数字相同,按照第二个数字从小到大,若第二个数字也相同,按照第三个数字从小到大。一个组合内的数字,按照从小到大的顺序输出。
花里胡哨的题目,就是求三个和为0的数字组合有几种
这题队友给力,AC了,我用的map过不了,,,,
队友两边找的,,,我的直接标记找,,,
AC代码:
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <map>
#include <set>
#include <queue>
#include <vector>
#include <algorithm>
#include <math.h>
using namespace std;
int v[3005];
int main(){
int n;
while(scanf("%d",&n) != EOF){
for(int i=0;i<n;i++){
scanf("%d",&v[i]);
}
sort(v,v+n);
for(int i=0;i<n-2;i++)
{
if(i>0&&v[i]==v[i-1])continue;
int l=i+1,r=n-1;
while(l<r)
{
if(v[i]+v[l]+v[r]<0)l++;
else if(v[i]+v[l]+v[r]>0)r--;
else if(v[i]+v[l]+v[r]==0)
{
printf("%d %d %d\n",v[i],v[l++],v[r--]);
while(l<r&&v[l]==v[l-1])l++;
while(l<r&&v[r]==v[r+1])r--;
}
}
}
}
return 0;
}
H - 丢失的数字
据说圣玛格丽特学院的图书馆上方住着一个金色妖精——维多利加,她有金色闪亮的头发和翡翠绿的双瞳,是个娇小宛如陶瓷娃娃般美丽容颜的少女。
“以智者知名,为愚者代言。”拥有智慧之泉的维多利加可是无所不知的哦~这不,数字收藏家涂山小八哭着跑来找她,说好盆友东方平平想送给她一个数字,但是自己的数字放的太乱了。
“我想找出我现在没有的最小正整数,让平平送给我,你能帮我找吗?”
嘛~维多利加这么可爱,当然会帮你啦~
Input
输入数据有多组,每组数据第一行输入一个整数n(1≤n≤106),表示小八拥有的数字个数。第二行输入n个整数ai(-109≤ai≤109),表示小八拥有的数字。
Output
对于每组输入数据,输出小八想让平平送给他的数字,每组输出占一行。
Sample Input
3
1 2 0
4
3 4 -1 1
Sample Output
3
2
Hint
数据量较大,建议使用scanf和printf输入输出。
给出数组找缺失的最小正整数
直接排个序然后找就行了,一开始我没考虑到数字一样的情况,wa了几次
队友提醒之后才做了更正
AC代码:
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <map>
#include <set>
#include <queue>
#include <vector>
#include <algorithm>
#include <math.h>
using namespace std;
int n;
int a[1000005];
int main(){
while(scanf("%d",&n)!=EOF){
memset(a,0,sizeof(a));
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
sort(a+1,a+1+n);
int j = 1;
for(int i=1;i<=n;i++){
if(a[i] < 1){
continue;
}else{
if(a[i-1] == a[i])
continue;
if(a[i] != j){
break;
}
else
j++;
}
}
printf("%d\n",j);
}
return 0;
}
I - 递归画图
递归图形是一类非常有意思的图形,今天介绍其中一种,点阵递归图(这个名字其实是随便起的)。点阵递归图有如下特点:
第一层若是:
第二层即为:
Input
输入数据有多组,第一行输入两个正整数a,b(ab<1000),表示边长为a的正方形第一层图形,b表示将要输出的b层图形,接下来是a行字符串,每行字符串包含a个字符,字符为空格或*。
Output
对于每组数据输出一个图形,每组输出后跟随一个空行。
Sample Input
Sample Output
Hint
输入输出为正方形图形,不是*的位置,保留空格占位。
emmm,貌似没有什么技巧,反正我是直接进行暴力的
能过就行,,,五层循环,,,
AC代码:
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <map>
#include <set>
#include <queue>
#include <vector>
#include <algorithm>
#include <math.h>
using namespace std;
string s[2005];
int main(){
int n,m;
while(cin>>n>>m){
getchar();
for(int i=0;i<2000;i++){
s[i] = "";
for(int j=0;j<2000;j++)
s[i] += ' ';
}
for(int i=0;i<n;i++){
getline(cin,s[i]);
}
for(int i=1;i<=m;i++){
for(int j=0;j<pow(n,i);j++){
for(int k=0;k<pow(n,i);k++){
if(s[j][k] == '*'){
int xx = 0,yy = 0;
for(int l=j*n;l<(j+1)*n;l++){
for(int h=k*n;h<(k+1)*n;h++){
s[l][h] = s[xx][yy++];
}
yy = 0;
xx++;
}
}else{
int xx = 0,yy = 0;
for(int l=j*n;l<(j+1)*n;l++){
for(int h=k*n;h<(k+1)*n;h++){
s[l][h] = ' ';
}
yy = 0;
xx++;
}
}
}
}
}
for(int i=0;i<pow(n,m);i++){
for(int j=0;j<pow(n,m);j++){
cout<<s[i][j];
}
cout<<endl;
}
cout<<endl;
}
return 0;
}
J - 电话拦截
小八用了点手段得知对手公司要做一个欺诈电话拦截app,小八立刻通知公司开发组,火速开发一个优质的欺诈电话拦截app,抢先一步上线。
小组技术总监给了一个方案,需要你来实现一下,首先用户可以标记电话号,标记成快递、骚扰、欺诈等。用户每收到一个电话,立即上传号码,经查找数据库,输出当前号码被标记次数最多的类型,以及被标记次数。如果有多于一种类型被匹配为最多次数,按照欺诈、骚扰、快递的优先级输出。
你作为小组成员,负责后台逻辑开发,现采用快速开发方案,开发一个功能预览版本。测试组成员已拟定好一组测试数据。
Input
输入数据有多组,每组数据先输入n(1≤n≤105)表示接下来的数据行数。接下来输入n行,输入按照时间顺序进行,有下面两种格式。
A 1234,表示接到一个电话1234。
B 1234 k,表示标记电话 1234 为快递。此处k、s、q分别表示快递、骚扰、欺诈。电话号码不超过20位。
Output
对于每组输入数据,输入为A 1234格式时,根据历史标记数据,匹配相应规则后,输出一个结果:
k=n:表示匹配“此电话被标记为快递n次”。
s=n:表示匹配“此电话被标记为骚扰n次”。
q=n:表示匹配“此电话被标记为欺诈n次”。
N:表示目前未被标记过。
输入为B 1234 k/s/q格式时,输出Y,表示已记录。
每组输出占一行。
Sample Input
7
A 1234
B 1234 k
A 1234
B 1234 k
B 1234 s
B 1234 s
A 1234
Sample Output
N
Y
k=1
Y
Y
Y
s=2
emmm模拟题,map里面存放结构体
AC代码:
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <map>
#include <set>
#include <queue>
#include <vector>
#include <algorithm>
#include <math.h>
using namespace std;
struct node
{
int k,s,q;
};
int main()
{
int n;
while(scanf("%d",&n) != EOF)
{
map<string,node>m;
while(n--)
{
string ss;
char b;
cin>>b;
if(b=='A')
{
cin>>ss;
if(m[ss].q==0&&m[ss].s==0&&m[ss].k==0)
{
printf("N\n");
}
else if(m[ss].q>=m[ss].s&&m[ss].q>=m[ss].k)
{
printf("q=%d\n",m[ss].q);
}
else if(m[ss].s>m[ss].q&&m[ss].s>=m[ss].k)
{
printf("s=%d\n",m[ss].s);
}
else if(m[ss].k>m[ss].q&&m[ss].k>m[ss].s)
{
printf("k=%d\n",m[ss].k);
}
}
if(b=='B')
{
char c;
cin>>ss>>c;
if(c=='k')
m[ss].k++;
if(c=='s')
m[ss].s++;
if(c=='q')
m[ss].q++;
printf("Y\n");
}
}
m.clear();
}
return 0;
}
经过组队赛之后发现自己非常菜,只能ac几道模拟题,,什么树啊,图啊,最短路径啥的算法都不会
看来以后算法这东西还是要搞,不然出几道模板题都不会写,那可就真的,,,,
不能拖全队的后腿啊!!烦躁