第一题:买菜
在一条街上有 n 个卖菜的商店,按 1 至 n 的顺序排成一排,这些商店都卖一种蔬菜。
第一天,每个商店都自己定了一个价格。
店主们希望自己的菜价和其他商店的一致,第二天,每一家商店都会根据他自己和相邻商店的价格调整自己的价格。
具体的,每家商店都会将第二天的菜价设置为自己和相邻商店第一天菜价的平均值(用去尾法取整)。
注意,编号为 1 的商店只有一个相邻的商店 2,编号为 n 的商店只有一个相邻的商店 n−1,其他编号为 i 的商店有两个相邻的商店 i−1 和 i+1。
给定第一天各个商店的菜价,请计算第二天每个商店的菜价。
输入格式
输入的第一行包含一个整数 n,表示商店的数量。
第二行包含 n 个整数,依次表示每个商店第一天的菜价。
输出格式
输出一行,包含 n 个正整数,依次表示每个商店第二天的菜价。
数据范围
对于所有评测用例,2≤n≤1000,第一天每个商店的菜价为不超过 1e4 的正整数。
输入样例:
8 4 1 3 1 6 5 17 9
输出样例:
2 2 1 3 4 9 10 13
解题思路:
根据题目进行模拟即可
cpp
#include<iostream>
using namespace std;
const int N = 1010;
int a[N];
int n;
int main()
{
cin >> n;
for(int i = 0;i < n;i ++) cin >> a[i];
cout << (a[0] + a[1]) / 2;
for(int i = 1;i < n - 1;i ++)
cout << " " << (a[i] + a[i - 1] + a[i + 1]) / 3;
cout << " " << (a[n - 2] + a[n - 1]) / 2;
return 0;
}
第二题:买菜
小 H 和小 W 来到了一条街上,两人分开买菜,他们买菜的过程可以描述为,去店里买一些菜然后去旁边的一个广场把菜装上车,两人都要买 n 种菜,所以也都要装 n 次车。
具体的,对于小 H 来说有 n 个不相交的时间段 [a1,b1],[a2,b2]...[an,bn]在装车,对于小 W 来说有 n 个不相交的时间段 [c1,d1],[c2,d2]...[cn,dn] 在装车。
其中,一个时间段 [s,t] 表示的是从时刻 s 到时刻 t 这段时间,时长为 t−s。
由于他们是好朋友,他们都在广场上装车的时候会聊天,他们想知道他们可以聊多长时间。
输入格式
输入的第一行包含一个正整数 n,表示时间段的数量。
接下来 n 行每行两个数 ai,bi,描述小 H 的各个装车的时间段。
接下来 n 行每行两个数 ci,di,描述小 W 的各个装车的时间段。
输出格式
输出一行,一个正整数,表示两人可以聊多长时间。
数据范围
对于所有的评测用例,1≤n≤2000,ai<bi<ai+1,ci<di<ci+1,对于所有的 i(1≤i≤n) 有,1≤ai,bi,ci,di≤1e6。
输入样例:
4 1 3 5 6 9 13 14 15 2 4 5 7 10 11 13 14
输出样例:
3
解题思路:
如果两个时间有交集一定是前一个的时间段的最后时刻,大于第二个时间段的开始时刻
根据这个思路最终答案一定是最小的终点时间 - 最大的开始时间
cpp
#include<iostream>
#include<cstring>
using namespace std;
#define x first
#define y second
typedef pair<int, int> PII;
const int N = 2010;
int n;
PII p[N], q[N];
int get(PII a, PII b)
{
if (a.y < b.x || b.y < a.x) return 0;
return min(a.y, b.y) - max(a.x, b.x);
}
int main()
{
cin >> n;
for (int i = 0; i < n; i ++ ) cin >> p[i].x >> p[i].y;
for (int i = 0; i < n; i ++ ) cin >> q[i].x >> q[i].y;
int res = 0;
for (int i = 0; i < n; i ++ )
for (int j = 0; j < n; j ++ )
res += get(p[i], q[j]);
cout << res << endl;
return 0;
}
第三题:元素选择器
题目略
解题思路:
模拟,数据量很小可以直接暴力搜索进行枚举
坑点:
(1)标签:大小写不敏感
(2)属性:大小写敏感
(3)后代选择器:从前往后找父节点,找到倒数第二个父节点的行号,从这个往后找满足最后一个元素的行号。
方法:
使用sstream进行读取
stringstream进行读取,不需要枚举位置
cpp
// 数据量很小
#include<iostream>
#include<sstream>
#include<vector>
using namespace std;
const int N = 110;
int n , m;
string s;
struct node
{
int type;
// id表示标签 main表示属性
string id , main;
}nodes[N];
string change(string t)
{
string res;
for(auto i : t)
{
if(i >= 'A' && i <= 'Z') res += (i ^ 32);
else res += i;
}
return res;
}
void work(vector<string>&v)
{
vector<int>res;
if(v.size() == 1)
{
// 属性 大小写敏感
if(v[0][0] == '#')
{
for(int i = 0;i < n;i ++)
if(nodes[i].main == v[0]) res.push_back(i + 1);
}
// 标签 大小写不敏感
else
{
for(int i = 0;i < n;i ++)
if(change(nodes[i].id) == change(v[0])) res.push_back(i + 1);
}
}
else
{
int w = v.size();
int j = 0 , temp = 0 , last = -1;
for(int i = 0;i < n;i ++)
{
if(j == w - 1)
{
temp = i;
break;
}
// 属性 大小写敏感
if(v[j][0] == '#')
{
if(v[j] == nodes[i].main && (last == -1 || nodes[i].type > last)) j ++ , last = nodes[i].type;
}
else
{
if(change(nodes[i].id) == change(v[j]) && (last == -1 || nodes[i].type > last)) j ++ , last = nodes[i].type;
}
}
if(j == w - 1)
{
for(int i = temp;i < n;i ++)
{
if(v[j][0] == '#')
{
if(v[j] == nodes[i].main && nodes[i].type > last) res.push_back(i + 1);
}
else
{
if(change(nodes[i].id) == change(v[j]) && nodes[i].type > last) res.push_back(i + 1);
}
}
}
}
cout << res.size() << " ";
for(int i = 0;i < res.size();i ++)
cout << res[i] << " ";
cout << endl;
}
int main()
{
cin >> n >> m;
getchar();
for(int i = 0;i < n;i ++)
{
getline(cin , s);
stringstream ss(s);
vector<string>v;
while(ss >> s) v.push_back(s);
int j = 0;
while(j < v[0].size() && v[0][j] == '.') j ++;
if(v.size() == 1) nodes[i] = {j / 2 , v[0].substr(j) , "****"};
else nodes[i] = {j / 2 , v[0].substr(j) , v[1]};
}
while(m --)
{
getline(cin , s);
stringstream ss(s);
vector<string>v;
while(ss >> s) v.push_back(s);
work(v);
}
return 0;
}
第四题:再买菜
在一条街上有 n 个卖菜的商店,按 1 至 n 的顺序排成一排,这些商店都卖一种蔬菜。
第一天,每个商店都自己定了一个正整数的价格。
店主们希望自己的菜价和其他商店的一致,第二天,每一家商店都会根据他自己和相邻商店的价格调整自己的价格。
具体的,每家商店都会将第二天的菜价设置为自己和相邻商店第一天菜价的平均值(用去尾法取整)。
注意,编号为 1 的商店只有一个相邻的商店 2,编号为 n 的商店只有一个相邻的商店 n−1,其他编号为 i 的商店有两个相邻的商店 i−1 和 i+1。
给定第二天各个商店的菜价,可能存在不同的符合要求的第一天的菜价,请找到符合要求的第一天菜价中字典序最小的一种。
字典序大小的定义:对于两个不同的价格序列 (a1,a2,...,an) 和 (b1,b2,b3,...,bn),若存在 i(i>=1),使得 ai<bi,且对于所有 j<i,aj=bj,则认为第一个序列的字典序小于第二个序列。
输入格式
输入的第一行包含一个整数 n,表示商店的数量。
第二行包含 n 个正整数,依次表示每个商店第二天的菜价。
输出格式
输出一行,包含 n 个正整数,依次表示每个商店第一天的菜价。
数据范围
对于 30% 的评测用例,2≤n≤5,第二天每个商店的菜价为不超过 10 的正整数;
对于 60% 的评测用例,2≤n≤20,第二天每个商店的菜价为不超过 100 的正整数;
对于所有评测用例,2≤n≤300,第二天每个商店的菜价为不超过 100 的正整数。
请注意,以上都是给的第二天菜价的范围,第一天菜价可能会超过此范围。
数据保证一定有解。
输入样例:
8 2 2 1 3 4 9 10 13
输出样例:
2 2 2 1 6 5 16 10
解题思路:
对于每一个除去开头和结尾的两个元素
对于第一个元素
对于最后一个元素
又因为是向下取整,其中a的元素是连续的可以使用前缀和进行
因此使用差分约束+spfa解决
差分约束:
a----->b ab间有一条边长度为c
s[b] >= s[a] + c
c有可能是负数因此需要使用spfa
得出下面的结论
求最小值 使用最长路 SPFA
求最大值 使用最短路
cpp
// 求最小值 使用最长路 SPFA
// 求最大值 使用最短路
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
const int N = 1e4 + 10;
int h[N] , ne[N] , w[N] , e[N] , idx;
int n , m;
int dist[N];
bool st[N];
void add(int a , int b , int c)
{
e[idx] = b , w[idx] = c , ne[idx] = h[a] , h[a] = idx ++;
}
void spfa()
{
// 最长路
queue<int>q;
// 最短路使用 memset(dist , 0x3f , sizeof dist);
memset(dist , -0x3f , sizeof dist);
dist[0] = 0;
q.push(0);
while(!q.empty())
{
int t = q.front();
q.pop();
st[t] = false;
for(int i = h[t];~i;i = ne[i])
{
int j = e[i];
if(dist[j] < dist[t] + w[i])
{
dist[j] = dist[t] + w[i];
if(!st[j])
{
q.push(j);
st[j] = true;
}
}
}
}
}
int b[N];
int main()
{
cin >> n;
memset(h , -1 , sizeof h);
for(int i = 1;i <= n;i ++) cin >> b[i];
/*
差分约束:
a----->b ab间有一条边长度为c
s[b] >= s[a] + c
c有可能是负数因此需要使用spfa
其中s为前缀和
对于不包括两边的元素
满足
b[i] = (a[i - 1] + a[i] + a[i + 1]) / 3
>>>> 3b[i] <= (s[i + 1] - s[i - 2]) <= 3b[i] + 2
>>>> 1、s[i + 1] - s[i - 2] >= 3b[i]
>>>> 2、3b[i] + 2 >= s[i + 1] - s[i - 2]
>>>> 1、s[i + 1] >= s[i - 2] + 3b[i]
>>>> 2、s[i - 2] >= s[i + 1] - 3b[i] - 2
>>>> 1、add(i - 2 , i + 1 , 3b[i]);
>>>> 2、add(i + 1 , i - 2 , -3b[i] - 2);
*/
for(int i = 2;i < n;i ++)
{
add(i - 2 , i + 1 , 3 * b[i]);
add(i + 1 , i - 2 , -3 * b[i] - 2);
}
/*
b[1] = (a[0] + a[1]) / 2
>>>> 2b[1] <= s[2] - s[0] <= 2b[1] + 1
>>>> 1、s[2] >= s[0] + 2b[1]
>>>> 2、s[0] >= s[2] - 2b[1] - 1
b[n] = (a[n] + a[n - 1]) / 2
>>>> 1、s[n - 2] >= s[n] - 2b[n] - 1
>>>> 2、s[n] >= s[n - 2] + 2b[n]
*/
add(0 , 2 , 2 * b[1]) , add(2 , 0 , -2 * b[1] - 1);
add(n - 2 , n , 2 * b[n]) , add(n , n - 2 , -2 * b[n] - 1);
// s[i] >= s[i - 1] + 1
for(int i = 1;i <= n;i ++) add(i - 1 , i , 1);
spfa();
/*
由于这里求出的是a数组的前缀和,题目要求输出a数组
则最终答案为: dist[i] - dist[i - 1]
*/
for(int i = 1;i <= n;i ++)
cout << dist[i] - dist[i - 1] << " ";
return 0;
}
第五题:线性递推式
感觉应该是DP+数学
cpp
#include <iostream>
#define ll long long
using namespace std;
const int mod=998244353;
const int M=1e5+10;
ll k[M],b[M];
ll l,r;
int m;
int main()
{
cin>>m>>l>>r;
for(int i=1;i<=m;i++) cin>>k[i];
b[0]=1;
for(int i=1;i<=r;i++)
{
ll ans=0;
for(int j=1;j<=min(i,m);j++)
{
ans=(ans+(k[j]*b[i-j]%mod))%mod;
}
b[i]=ans;
}
for(int i=l;i<=r;i++)cout<<b[i]<<endl;
return 0;
}