第一题:打酱油
小明带着 N 元钱去买酱油。
酱油 10 块钱一瓶,商家进行促销,每买 3 瓶送 1 瓶,或者每买 5 瓶送 2 瓶。
请问小明最多可以得到多少瓶酱油。
输入格式
输入的第一行包含一个整数 N,表示小明可用于买酱油的钱数。
输出格式
输出一个整数,表示小明最多可以得到多少瓶酱油。
数据范围
N 是 10 的整数倍,N 不超过 300。
输入样例1:
40
输出样例1:
5
样例1解释
把 40 元分成 30 元和 10 元,分别买 3 瓶和 1 瓶,其中 3 瓶送 1 瓶,共得到 5 瓶。
输入样例2:
80
输出样例2:
11
样例2解释
把 80 元分成 30 元和 50 元,分别买 3 瓶和 5 瓶,其中 3 瓶送 1 瓶,5 瓶送 2 瓶,共得到 11 瓶。
解题思路:
暴力搜索,使用深度优先遍历,枚举每一种情况,计算出所使用的瓶子个数。
#include<iostream>
using namespace std;
int res = 0;
void dfs(int u , int cnt)
{
if(u < 0) return ;
else if(u == 0)
{
res = max(res , cnt);
return ;
}
dfs(u - 10 , cnt + 1);
dfs(u - 30 , cnt + 4);
dfs(u - 50 , cnt + 7);
}
int main()
{
int n;
cin >> n;
dfs(n , 0);
cout << res << endl;
return 0;
}
第二题:公共钥匙盒
有一个学校的老师共用 N 个教室,按照规定,所有的钥匙都必须放在公共钥匙盒里,老师不能带钥匙回家。
每次老师上课前,都从公共钥匙盒里找到自己上课的教室的钥匙去开门,上完课后,再将钥匙放回到钥匙盒中。
钥匙盒一共有 N 个挂钩,从左到右排成一排,用来挂 N 个教室的钥匙。
一串钥匙没有固定的悬挂位置,但钥匙上有标识,所以老师们不会弄混钥匙。
每次取钥匙的时候,老师们都会找到自己所需要的钥匙将其取走,而不会移动其他钥匙。
每次还钥匙的时候,还钥匙的老师会找到最左边的空的挂钩,将钥匙挂在这个挂钩上。
如果有多位老师还钥匙,则他们按钥匙编号从小到大的顺序还。
如果同一时刻既有老师还钥匙又有老师取钥匙,则老师们会先将钥匙全还回去再取出。
今天开始的时候钥匙是按编号从小到大的顺序放在钥匙盒里的。
有 K 位老师要上课,给出每位老师所需要的钥匙、开始上课的时间和上课的时长,假设下课时间就是还钥匙时间,请问最终钥匙盒里面钥匙的顺序是怎样的?
输入格式
输入的第一行包含两个整数 N,K。
接下来 K 行,每行三个整数 w,s,c,分别表示一位老师要使用的钥匙编号、开始上课的时间和上课的时长。可能有多位老师使用同一把钥匙,但是老师使用钥匙的时间不会重叠。
保证输入数据满足输入格式,你不用检查数据合法性。
输出格式
输出一行,包含 N 个整数,相邻整数间用一个空格分隔,依次表示每个挂钩上挂的钥匙编号。
数据范围
对于 30% 的评测用例,1≤N,K≤10,1≤w≤N,1≤s,c≤30;
对于 60% 的评测用例,1≤N,K≤50,1≤w≤N,1≤s≤300,1≤c≤50,
对于所有评测用例,1≤N,K≤1000,1≤w≤N,1≤s≤10000,1≤c≤100。输入样例1:
5 2 4 3 3 2 2 7
输出样例1:
1 4 3 2 5
样例1解释
第一位老师从时刻 3 开始使用 4 号教室的钥匙,使用 3 单位时间,所以在时刻 6 还钥匙。
第二位老师从时刻 2 开始使用钥匙,使用 7 单位时间,所以在时刻 9 还钥匙。
每个关键时刻后的钥匙状态如下(X表示空):
时刻 2 后为 1X345;
时刻 3 后为 1X3X5;
时刻 6 后为 143X5;
时刻 9 后为 14325。输入样例2:
5 7 1 1 14 3 3 12 1 15 12 2 7 20 3 18 12 4 21 19 5 30 9
输出样例2:
1 2 3 5 4
解题思路:
使用结构体进行存储时间信息。
如果需要取钥匙,那么就枚举每一个钥匙编号,判断该位置是否需要取出,如果取出就将其置为0
如果需要放钥匙,那么就枚举出编号为0的第一个位置,将其置为当前id
注意首先需要对于时间进行排序。
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 10010;
struct time_p
{
int id , s , type;
}ti[N];
int n , k;
int res[N];
bool cmp(time_p a , time_p b)
{
if(a.s != b.s) return a.s < b.s;
if(a.type != b.type) return a.type > b.type;
return a.id < b.id;
}
int main()
{
cin >> n >> k;
int cnt = 0;
while(k --)
{
int a , b , c;
cin >> a >> b >> c;
ti[cnt ++] = {a , b , 0}; // 取钥匙
ti[cnt ++] = {a , b + c , 1}; // 放钥匙
}
sort(ti , ti + cnt , cmp);
for (int i = 1; i <= n; i ++ ) res[i] = i;
for (int i = 0; i < cnt; i ++ )
{
int id = ti[i].id;
if (!ti[i].type) // 取钥匙
{
for (int j = 1; j <= n; j ++ )
if (res[j] == id)
{
res[j] = 0;
break;
}
}
else
{
for (int j = 1; j <= n; j ++ )
if (!res[j])
{
res[j] = id;
break;
}
}
}
for (int i = 1; i <= n; i ++ )
cout << res[i] << ' ';
return 0;
}
第三题:JSON查询
JSON (JavaScript Object Notation) 是一种轻量级的数据交换格式,可以用来描述半结构化的数据。
JSON 格式中的基本单元是值 (value),出于简化的目的本题只涉及 2 种类型的值:
- 字符串 (string):字符串是由双引号
"
括起来的一组字符(可以为空)。如果字符串的内容中出现双引号"
,在双引号前面加反斜杠,也就是用\"
表示;如果出现反斜杠\
,则用两个反斜杠\\
表示。反斜杠后面不能出现"
和\
以外的字符。例如:""、"hello"、"\"\\"
。- 对象 (object):对象是一组键值对的无序集合(可以为空)。键值对表示对象的属性,键是属性名,值是属性的内容。对象以左花括号
{
开始,右花括号}
结束,键值对之间以逗号,
分隔。一个键值对的键和值之间以冒号:
分隔。键必须是字符串,同一个对象所有键值对的键必须两两都不相同;值可以是字符串,也可以是另一个对象。例如:{}、{"foo": "bar"}、{"Mon": "weekday", "Tue": "weekday", "Sun": "weekend"}
。除了字符串内部的位置,其他位置都可以插入一个或多个空格使得 JSON 的呈现更加美观,也可以在一些地方换行,不会影响所表示的数据内容。
例如,上面举例的最后一个 JSON 数据也可以写成如下形式。
{ "Mon": "weekday", "Tue": "weekday", "Sun": "weekend" }
给出一个 JSON 格式描述的数据,以及若干查询,编程返回这些查询的结果。
输入格式
第一行是两个正整数 n 和 m,分别表示 JSON 数据的行数和查询的个数。
接下来 n 行,描述一个 JSON 数据,保证输入是一个合法的 JSON 对象。
接下来 m 行,每行描述一个查询。给出要查询的属性名,要求返回对应属性的内容。需要支持多层查询,各层的属性名之间用小数点
.
连接。保证查询的格式都是合法的。输出格式
对于输入的每一个查询,按顺序输出查询结果,每个结果占一行。
如果查询结果是一个字符串,则输出
STRING <string>
,其中<string>
是字符串的值,中间用一个空格分隔。如果查询结果是一个对象,则输出
OBJECT
,不需要输出对象的内容。如果查询结果不存在,则输出
NOTEXIST
。数据范围
n≤100,每行不超过 80 个字符。
m≤100,每个查询的长度不超过 80 个字符。
字符串中的字符均为 ASCII 码 33−126 的可打印字符,不会出现空格。所有字符串都不是空串。
所有作为键的字符串不会包含小数点.
。查询时键的大小写敏感。
50% 的评测用例输入的对象只有 1 层结构,80% 的评测用例输入的对象结构层数不超过 2 层。
举例来说,{"a": "b"}
是一层结构的对象,{"a": {"b": "c"}}
是二层结构的对象,以此类推。输入样例:
10 5 { "firstName": "John", "lastName": "Smith", "address": { "streetAddress": "2ndStreet", "city": "NewYork", "state": "NY" }, "esc\\aped": "\"hello\"" } firstName address address.city address.postal esc\aped
输出样例:
STRING John OBJECT STRING NewYork NOTEXIST STRING "hello"
解题思路:
可以使用python中的stdin进行读入,然后使用eval转化为字典,然后即可判断出来
from sys import stdin
n, m = map(int , input().split())
str = ""
for i in range(n):
str += stdin.readline()
obj = eval(str)
def query(qs):
o = obj
for s in qs:
# 判断是否是{}字典
if type(o) is not dict or s not in o:
print("NOTEXIST")
return
else:
o = o[s]
# 字典输出object
if type(o) is dict:
print("OBJECT")
else:
# 字符串输出字符串中的内容
print("STRING %s" % (o))
for i in range(m):
qs = input().split('.')
query(qs)
第四题:通信网络
某国的军队由 N 个部门组成,为了提高安全性,部门之间建立了 M 条通路,每条通路只能单向传递信息,即一条从部门 a 到部门 b 的通路只能由 a 向 b 传递信息。
信息可以通过中转的方式进行传递,即如果 a 能将信息传递到 b,b 又能将信息传递到 c,则 a 能将信息传递到 c。
一条信息可能通过多次中转最终到达目的地。
由于保密工作做得很好,并不是所有部门之间都互相知道彼此的存在。
只有当两个部门之间可以直接或间接传递信息时,他们才彼此知道对方的存在。
部门之间不会把自己知道哪些部门告诉其他部门。
上图中给了一个 4 个部门的例子,图中的单向边表示通路。
部门 1 可以将消息发送给所有部门,部门 4 可以接收所有部门的消息,所以部门 1 和部门 4 知道所有其他部门的存在。
部门 2 和部门 3 之间没有任何方式可以发送消息,所以部门 2 和部门 3 互相不知道彼此的存在。
现在请问,有多少个部门知道所有 N 个部门的存在。
或者说,有多少个部门所知道的部门数量(包括自己)正好是 N。
输入格式
输入的第一行包含两个整数 N,M,分别表示部门的数量和单向通路的数量。所有部门从 1 到 N 标号。
接下来 M 行,每行两个整数 a,b,表示部门 a 到部门 b 有一条单向通路。
输出格式
输出一行,包含一个整数,表示答案。
数据范围
对于 30% 的评测用例,1≤N≤10,1≤M≤20;
对于 60% 的评测用例,1≤N≤100,1≤M≤1000;
对于 100% 的评测用例,1≤N≤1000,1≤M≤10000。输入样例:
4 4 1 2 1 3 2 4 3 4
输出样例:
2
样例解释
部门 1 和部门 4 知道所有其他部门的存在。
解题思路:
正向建图和反向建图,然后做一遍dfs走一遍图。统计出正向和反向之后的都知道的部门数。
#include<iostream>
#include<cstring>
using namespace std;
const int N = 1010 , M = 20010;
int n , m;
bool st[M];
bool st1[M];
int h[M] , h1[M] , ne[M] , e[M] , idx;
void add(int h[] , int a , int b)
{
e[idx] = b , ne[idx] = h[a] , h[a] = idx ++;
}
void dfs(int u , bool st[] , int h[])
{
st[u] = true;
for(int i = h[u];~i;i = ne[i])
{
int j = e[i];
if(!st[j]) dfs(j , st , h);
}
}
int main()
{
cin >> n >> m;
memset(h , -1 , sizeof h);
memset(h1 , -1 , sizeof h1);
while(m --)
{
int a , b;
cin >> a >> b;
add(h , a , b) , add(h1 , b , a);
}
int res = 0;
for(int i = 1;i <= n;i ++)
{
memset(st , 0 , sizeof st);
memset(st1 , 0 , sizeof st1);
dfs(i , st , h) , dfs(i , st1 , h1);
int t = 0;
for(int j = 1;j <= n;j ++)
if(st[j] || st1[j]) t ++;
if(t == n) res ++;
}
cout << res << endl;
return 0;
}
第五题:除法
使用线段树或是树状数组就行
#include <iostream>
#include <cstring>
#include <algorithm>
#include <set>
using namespace std;
typedef long long LL;
const int N = 100010, M = 1000010;
int n, m;
set<int> pos[M];
LL tr[N];
set<int> vs;
struct Query
{
int t, l, r, v;
}q[N];
int w[N];
int lowbit(int x)
{
return x & -x;
}
void add(int x, int v)
{
for (int i = x; i <= n; i += lowbit(i)) tr[i] += v;
}
LL query(int x)
{
LL res = 0;
for (int i = x; i; i -= lowbit(i)) res += tr[i];
return res;
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++ )
{
scanf("%d", &w[i]);
add(i, w[i]);
}
for (int i = 0; i < m; i ++ )
{
int t, l, r, v;
scanf("%d%d%d", &t, &l, &r);
if (t == 1)
{
scanf("%d", &v);
q[i] = {t, l, r, v};
if (v != 1) vs.insert(v);
}
else q[i] = {t, l, r};
}
for (int i = 1; i <= n; i ++ )
for (int j = 1; j * j <= w[i]; j ++ )
if (w[i] % j == 0)
{
if (vs.count(j)) pos[j].insert(i);
if (w[i] / j != j && vs.count(w[i] / j))
pos[w[i] / j].insert(i);
}
for (int i = 0; i < m; i ++ )
if (q[i].t == 1)
{
int v = q[i].v;
auto it = pos[v].lower_bound(q[i].l);
while (it != pos[v].end() && *it <= q[i].r)
{
int k = *it;
it ++ ;
add(k, -w[k] + w[k] / v);
for (int j = 1; j * j <= w[k]; j ++ )
if (w[k] % j == 0)
{
pos[j].erase(k);
if (w[k] / j != j) pos[w[k] / j].erase(k);
}
w[k] /= v;
for (int j = 1; j * j <= w[k]; j ++ )
if (w[k] % j == 0)
{
if (vs.count(j)) pos[j].insert(k);
if (w[k] / j != j && vs.count(w[k] / j))
pos[w[k] / j].insert(k);
}
}
}
else printf("%lld\n", query(q[i].r) - query(q[i].l - 1));
return 0;
}
30分直接到手
#include<iostream>
using namespace std;
const int N = 1e5 + 10;
int n , m;
int a[N];
int main()
{
scanf("%d %d" ,&n ,&m);
for(int i = 1;i <= n;i ++)
scanf("%d" ,&a[i]);
while(m --)
{
int op;
scanf("%d" ,&op);
if(op == 1)
{
int l , r , v;
scanf("%d %d %d" ,&l ,&r ,&v);
for(int i = l;i <= r;i ++)
if(a[i] % v == 0) a[i] /= v;
}
else
{
int l , r;
scanf("%d %d" ,&l ,&r);
int sum = 0;
for(int i = l;i <= r;i ++)
sum += a[i];
printf("%d\n" , sum);
}
}
return 0;
}