九题
B 正则表达式
来源:牛客网
题目描述
正则表达式(英语:Regularexpression ,常简写为 regex或 RE),又称规律表达式、正则表示式、正则表示法、规则表达式、常规表示法,是计算机科学概念,用简单字符串来描述、匹配文中全部匹配指定格式的字符串,现在很多文本编辑器都支持用正则表达式搜索、取代匹配指定格式的字符串。
许多程序设计语言都支持用正则表达式操作字符串,如Perl就内置功能强大的正则表达式引擎。正则表达式这概念最初由Unix的工具软件(例如sed 和 grep)普及开。
Third 最近深入学习了正则表达式,现在他得到了一些数据,希望从中找出一些 IP 地址,但是 Third 今天已经学习了一整天,现在他要把这个任务交给你,请你帮他完成。
但是我们都知道这是新生赛,为了让大家做的愉快,Third决定只让你分析一些简单的数据。
具体来说,给你 n 个IP地址,每个IP为以下形式:
x.x.x.x,其中 xxx 表示一个十进制数字, ... 没有特殊含义,表示其本身。
你需要判断有多少数据表示的 IPIPIP 地址是正确的(正确的 IP 地址其满足以下条件:∀x∈[0,255])。
输入描述:
第一行一个正整数 n,表示有 n 个 IP 地址。
接下来 n 行,每行一个 IP 地址。
数据保证 0≤x,n≤10000
输出描述:
一个正整数,表示正确 IPIPIP 地址的数量。
示例1
输入
4
8.8.8.8
8.8.4.4
192.168.1.1
192.168.1.256
输出
3
示例2
输入
3
10.12.26.239
888.90.8.0
4.9.2.8
输出
2
代码:
cpp
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,ans,x;
char c;
bool b;
signed main(){
cin>>n;
while(n--){
b=0;
for(int i=0;i<4;i++){
if(i==3){
cin>>x;
if(x<0||x>255){
b=1;
}
}
else {
cin>>x>>c;
if(x<0||x>255){
b=1;
}
}
}
if(b==0){
ans++;
}
}
cout<<ans<<'\n';
return 0;
}
C Circle
来源:牛客网
题目描述
一共 ttt 组询问,每组询问之间相互独立。
对于每组询问,给定一个整数 n,求 n个圆(半径可以不同)可以分割的最大区域数为多少?
输入描述:
第一行包含一个正整数 t(1≤t≤103)------测试用例的数量。
接下来一行,t 个用空格隔开的整数 n(0≤n≤106),依次表示每组询问给定的圆形个数。
输出描述:
一行,对于每次询问输出一个整数表示结果,每个整数之间用空格隔开。
示例1
输入
4
0 1 2 3
输出
1 2 4 8
代码:
cpp
#include<bits/stdc++.h>
#define int long long
using namespace std;
int t,n;
signed main(){
cin>>t;
while(t--){
cin>>n;
if(n==0)cout<<1<<" ";
else{
cout<<n*(n-1)+2<<" ";
}
}
return 0;
}
E 区间
来源:牛客网
题目描述
在一个长度为n的纸带上,初始时所有位置颜色为白色,现在要执行以下两种操作一共q次
操作一:输入一个下标x,你需要将位置x的颜色翻转(白色变为黑色,黑色变为白色)
操作二; 输入两个正整数L,R你需要输出区间[[L,R]中的连续的白色区间长度最大值
输入描述:
第一行输入两个正整数n,q,1≤n,q≤105
第二行到第q+1q+1q+1行,每行先给出一个正整数op,如果op=1代表操作一,op=2代表操作二
输入格式如下:
操作一:op,x
操作二: op,L,R
输出描述:
每次进行操作二后每行输出一个非负整数代表答案
示例1
输入
4 3
1 2
2 1 4
2 1 3
输出
2
1
思路:
用ve存储所有黑点的位置,op为1,找到黑点位置,则删除,没有则插入黑点
找到两个黑点之间的距离即为连续区间的值
代码:
cpp
#include <bits.stdc++.h>
using namespace std;
#define int long long
int n, q, op, l, r;
vector<int> ve;
signed main() {
cin >> n >> q;
while (q--) {
cin >> op;
if (op == 1) {
int x;
cin >> x;
auto t = lower_bound(ve.begin(), ve.end(), x);
if (t == ve.end() || *t != x) { // 如果元素 x 不存在,插入它
ve.insert(t, x);
} else { // 如果元素 x 存在,删除它
ve.erase(t);
}
}
if (op == 2) {
cin >> l >> r;
auto st = lower_bound(ve.begin(), ve.end(), l); // 找到范围内的起始位置
if (st == ve.end() || *st > r) { // 如果范围内没有元素,或起始元素大于 r
cout << r - l + 1 << '\n';
continue;
}
int ans = *st - l; // 初始化答案为第一个片段的长度
int k = *st; // k 是当前片段的结束位置,从 *st 开始
st++; // 移动到下一个元素
// 遍历范围内的元素
while (st != ve.end() && *st <= r) {
int ed = *st; // ed 是当前片段的结束位置
if (ed - k - 1 > ans) // 如果当前片段长度大于答案,更新答案
ans = ed - k - 1;
k = *st; // 更新 k 到当前片段的结束位置
st++; // 移动到下一个元素
}
ans = max(ans, r - k);
cout << ans << '\n';
}
}
return 0;
}
F 累加器
来源:牛客网
题目描述
存在一个累加器,每次可以对一个数进行加 1 操作,此时在二进制下有一些位发生改变,对一个数 x 进行 y 次累加操作,总共有多少位发生改变。
输入描述:
第一行一个正整数 T (1≤T≤105)代表多组询问。
接下来 T 行 每行两个正整数 x,y(1≤x,y≤106),代表对 x 进行 y 次累加操作。
输出描述:
T 行每组询问一行代表总共发生改变的位数。
示例1
输入
4
1 4
10 1
20 20
1 100
输出
7
1
40
197
说明
对于第一个样例开始 (0001)2进行 4 次累加。
第一次 (0010)2 两位改变。
第二次 (0011)2 一位改变。
第三次 (0100)2 三位改变。
第四次 (0101)2一位改变。
思路:
寻找二进制变化的规律,最后一位每次加一都会变化,倒数第二位会在倒数第一位变化两次再进行变化,以此类推,将数字到1的过程的变化数量求出
代码:
cpp
#include<bits/stdc++.h>
#define int long long
using namespace std;
int t,x,y,ans,sum;
int bh(int x){
int ans=0,n=1;
while(n<=x){
ans+=x/n;
n*=2;
}
return ans;
}
signed main() {
cin>>t;
while(t--){
cin>>x>>y;
sum=x+y;
cout<<bh(x+y)-bh(x)<<'\n';
}
return 0;
}
G 求值
来源:牛客网
题目描述
现有三个正整数 A,B,C,请你找三个整数x,y,z满足x+y+z=n,且0≤x,y,z,使得 ∣x∗A+y∗B+z∗C−W∣ 最小。
为了简化题目,现在只要找到∣x∗A+y∗B+z∗C−W∣的最小值。
输入描述:
第一行一个正整数 T(1≤T≤103)代表多组询问
接下来 TTT 行 每行五个正整数 A,B,C,n,W(1≤A,B,C,n,W≤106)如题意所示
保证所有样例中 n 的和小于 10^6
输出描述:
T 行每组询问输出一行,代表最小答案
示例1
输入
4
1 2 3 4 5
6 7 8 9 10
3 4 5 6 7
100 200 33 23 4
输出
0
44
11
755
代码:
添加判断条件
cpp
#include<bits/stdc++.h>
#define int long long
using namespace std;
signed main() {
int T;
cin >> T;
while (T--) {
bool b1=0;
int a[4], n, W;
for(int i=1;i<=3;i++){
cin>>a[i];
}
sort(a+1,a+4);
cin >> n >> W;
if(a[1]*n>=W){
cout<<a[1]*n-W<<'\n';
}
else {
int minx = 1e15;
for (int x = 0; x <= n; ++x) {
for (int y = 0; y <= n - x; ++y) {
b1=0;
int z = n - x - y;
int d = abs(x * a[1] + y * a[2] + z * a[3] - W);
if(d==0){
minx=0;
b1=1;
break;
}
if (d < minx) {
minx = d;
}
}
if(b1==1){
break;
}
}
cout << minx << endl;
}
}
return 0;
}
I 游戏
来源:牛客网
题目描述
给定 n 个点, m 条边的无向图
每条边有一个花费和状态,状态为 0 表示该边处于锁定状态暂时不可通过, 1 表示可以通过
在节点 k有一把钥匙,你取得钥匙后,便可以正常通过 0 状态边
现在你从 1 节点出发,需要求出到达节点 n 的最小花费
输入描述:
第一行三个整数 n,m,k,分别表示节点数,边数,钥匙所在节点
接下来 m 行,每行四个整数 ai,bi,ci,di ,表示 ai到 bi 之间存在一条无向边,通过该边花费 ci,其状态为 di , di取值仅为 0或 1
输出描述:
输出节点 1 到 n 的最小花费,如果无法到达,输出 −1
示例1
输入
6 10 5
1 2 1 1
2 4 9 1
4 5 4 1
1 3 9 1
3 6 8 0
4 6 6 0
4 5 1 0
5 6 10 0
5 6 5 0
5 6 6 1
输出
19
示例2
输入
6 10 5
1 6 4 1
6 3 9 1
3 5 8 1
1 2 10 0
3 4 2 1
4 5 2 0
3 4 5 1
3 6 6 1
5 6 1 0
3 5 10 1
输出
4
备注:
1≤n≤2×105,0≤m≤105,1≤k,ai,bi≤n,1≤ci≤2×105
思路:
最短路+先求为1,可通过的路的最短路,再找到钥匙所在处,再添加0的路径求最短路
代码:
cpp
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,k,dist[200005],sum1,sum2,sum3,sum;
vector<int>u1,yy,v1;
struct node{
int y,v;
node(int _y,int _v){
y=_y;
v=_v;
}
};
vector<node>edge[200005];
set<pair<int,int>>se;
void csh(){
for(int i=0;i<200005;i++){
dist[i]=1e15;
}
}
void dij(int s){
csh();
dist[s]=0;
se.clear();
for(int i=0;i<=n;i++){
se.insert(make_pair(dist[i],i));
}
while(!se.empty()){
int x=se.begin()->second;
se.erase(se.begin());
for(auto i:edge[x]){
if(dist[x]+i.v<dist[i.y]){
se.erase(make_pair(dist[i.y],i.y));
dist[i.y]=dist[x]+i.v;
se.insert(make_pair(dist[i.y],i.y));
}
}
}
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>m>>k;
for(int i=0;i<m;i++){
int u,y,v,s;
cin>>u>>y>>v>>s;
if(s==1){
edge[u].push_back(node(y,v));
edge[y].push_back(node(u,v));
}
else {
u1.push_back(u);
yy.push_back(y);
v1.push_back(v);
}
}
dij(1);
sum1=dist[n];
sum2=dist[k];
for(int i=0;i<u1.size();i++){
edge[u1[i]].push_back(node(yy[i],v1[i]));
edge[yy[i]].push_back(node(u1[i],v1[i]));
}
dij(k);
sum3=dist[n];
sum=min(sum3+sum2,sum1);
if(sum>=1e15) cout<<"-1";
else cout<<sum;
return 0;
}
J keillempkill学姐の卷积
来源:牛客网
题目描述
计算机视觉是一个非常有趣且充满挑战的领域。特别是卷积神经网络(CNN),这种网络在图像识别和处理方面展示了惊人的效果。keillempkill学姐意识到,要深入理解CNN,就必须从其最基本的组成部分------卷积操作开始。卷积操作本质上是一个元素乘积和的过程,卷积核在图像上滑动并在每个位置执行这种运算。
给定一个 n×n的卷积核和一个 m×m 的矩阵。你的任务是使用卷积核对图像矩阵进行卷积操作。卷积操作是指,将卷积核覆盖到矩阵的对应部分,并将卷积核下的元素与矩阵对应位置的元素相乘,然后将所有乘积相加,得到结果矩阵的一个元素。卷积核会在整个矩阵上移动,直到覆盖矩阵的每一个可以容纳卷积核的部分。
例如:
输入描述:
第一行包含两个整数 n 和 m,(1≤n≤m≤20)
接下来 n 行,每行 n 个整数 ai,j(0≤ai,j≤20),表示卷积核。
接下来 m 行,每行 m 个整数 bi,j(0≤bi,j≤20) ,表示需要进行卷积的矩阵。
输出描述:
输出一个 (m−n+1)×(m−n+1)(m-n+1) 的矩阵,表示卷积操作的结果。
示例1
输入
2 3
0 1
2 3
1 2 3
4 5 6
7 8 9
输出
25 31
43 49
示例2
输入
2 4
0 1
2 3
1 2 3 4
5 6 7 8
9 10 11 12
12 14 15 16
输出
30 36 42
54 60 66
76 84 90
代码:
cpp
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,a[25][25],b[25][25],sum,xj,xi,ans;
signed main() {
cin >> n >> m;
int a[25][25], b[25][25];
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
cin >> a[i][j];
}
}
for(int i = 1; i <= m; i++) {
for(int j = 1; j <= m; j++) {
cin >> b[i][j];
}
}
for(int i = 1; i <= m - n + 1; i++) {
for(int j = 1; j <= m - n + 1; j++) {
sum = 0;
for(int k = 1; k <= n; k++) {
for(int l = 1; l <= n; l++) {
sum += a[k][l] * b[i+k-1][j+l-1];
}
}
cout << sum << " ";ans++;
if(ans==m-n+1){
cout<<'\n';
ans=0;
}
}
}
return 0;
}
K 暴食之史莱姆
来源:牛客网
题目描述
有n只史莱姆排成一条线,史莱姆们从左到右编号依此为1到n。第iii只史莱姆的体积为ai
史莱姆可以吃掉他的邻居,当且仅当他的体积大于等于邻居时,但是受到世界规则的限制,他的体积会变为被吃掉的邻居的体积。
在满足题意情况下每个史莱姆都可以被吃掉,在最优情况下,每个史莱姆最多可以吃多少个同伴。
输入描述:
第一行包含一个整数nnn(1≤n≤2⋅105)
第二行包含n个整数a[1],a[2]....,a[n](0≤a[i]≤109)
输出描述:
一行,用空格隔开的 n 个整数。第 i 个整数表示第 i 个史莱姆最多可以吃多少个同伴。
示例1
输入
4
1 4 2 4
输出
0 2 1 2
示例2
输入
5
1 2 3 4 5
输出
0 1 2 3 4
备注:
只要满足题目条件所有的史莱姆均可以吃掉自己相邻的史莱姆。
样例一:
对于1号史莱姆,显然无法吃掉任何一个史莱姆,所以最多吃0个;
对于2号史莱姆,可以先吃3号史莱姆他的体积变为2然后他再吃掉1号史莱姆体积变为1,所以最多吃2个;
对于3号史莱姆,先让2号史莱姆吃掉1号史莱姆,2号史莱姆的体积变为1,再让3号史莱姆吃到2号史莱姆。所以最多吃1个;
对于4号史莱姆,先让4号史莱姆吃掉3号史莱姆这时候4号体积变为2。让2号史莱姆吃掉1号史莱姆这时候2号史莱姆的体积为1,再让4号史莱姆吃掉2号史莱姆,所以最多吃2个。
思路:
stack<int> l 和 stack<int> r 分别用于往右和往左的单调栈。
l (r)栈用于记录从左往右过程中当前位置之前所有比当前史莱姆体积小的史莱姆,确定每个史莱姆能吃掉的同伴数量。
代码:
cpp
#include <bits/stdc++.h>
using namespace std;
int a[200005];
int ans1[200005],ans2[200005];
stack<int> l, r;
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n;
cin >> n;
for(int i=1;i<=n;i++) {
cin >> a[i];
}
for(int i=1;i<=n;i++) {
while(l.size() && l.top() > a[i]) l.pop();
ans1[i] = l.size();
l.push(a[i]);
}
for(int i=n;i>=1;i--) {
while(r.size() && r.top() > a[i]) r.pop();
ans2[i] = r.size();
r.push(a[i]);
}
for(int i=1;i<=n;i++) {
cout << ans1[i] + ans2[i] << ' ';
}
return 0;
}
L SSH
来源:牛客网
题目描述
现在,你需要实现一个超级无敌简单的简化版的 SSH 服务,以验证用户的身份。
具体来说,给你 m 个密钥对,每个密钥对包含一个公钥和一个私钥
另有 n 台主机,每台主机都有一个唯一的 IPv4 地址和一定数量的用户,用户以用户名区分,同一台主机上的用户不能重名。每个用户有仅属于自己的一些公钥
然后是 q 次查询,每次查询给出一个用户名,一个 IPv4 地址以及此次登录使用的私钥,要求你判断该 IPv4 地址对应的主机上的用户,是否拥有这个私钥对应的公钥
输入描述:
第一行包含三个整数 m, n, q (1 ≤ m, q ≤ 100, 1 ≤ n ≤ 10)
接下来 m 行,每行包含两个字符串 pub, pri,表示一个密钥对,pub 是公钥,pri 是私钥,长度均不超过 10,且只包含小写字母
接下来是 n 组数据,每组数据的格式如下:
第一行包含一个字符串 ip 和 一个整数 k (1 ≤ k ≤ 10),表示一台主机的 IPv4 地址和用户数量
然后是 k 行,每行包含一个字符串 user ,一个整数 t (1 ≤ t ≤ 10) 和 t 个字符串,表示一个用户的用户名,公钥数量,以及公钥
接下来是 q 行,每行包含一个字符串 user, 一个字符串 ip 和一个字符串 pri,表示一次查询,即一个用户名,一个 IPv4 地址和一个私钥
输出描述:
对于每次查询,输出一行,如果该用户名对应的用户在该 IPv4 地址对应的主机上,并且拥有这个私钥对应的公钥,输出 Yes,否则输出 No
示例1
输入
3 2 2
ab cd
ef gki
lmn opq
1.1.1.1 2
alice 2 ab ef
bob 1 ef
8.8.8.8 2
googel 1 lmn
gg 3 ab ef lmn
googel 8.8.8.8 opq
bob 1.1.1.1 gki
输出
Yes
Yes
说明
8.8.8.8主机上的用户googel的公钥lmn对应私钥opq,登陆成功
1.1.1.1主机上的用户bob的公钥ef对应私钥gki,登陆成功
示例2
输入
3 1 1
a b
c d
e f
127.0.0.1 1
user 1 a
users 127.0.0.1 b
输出
No
说明
127.0.0.1主机上并不存在users用户
代码:
cpp
#include <bits/stdc++.h>
#define int long long
using namespace std;
int m, n, q;
string pub, pri, dip;
map<string, string> mp;
bool b,b1;
struct S {
string ip;
string name;
int ge1;
string ss[105];
} a[105];
signed main() {
cin >> m >> n >> q;
for (int i = 0; i < m; i++) {
cin >> pub >> pri;
mp[pri] = pub;
}
int c = 0;
for (int i = 0; i < n; i++) {
int ge;
cin >> dip >> ge;
for (int j = 0; j < ge; j++) {
a[c].ip = dip;
cin >> a[c].name >> a[c].ge1;
for (int k = 0; k < a[c].ge1; k++) {
cin >> a[c].ss[k];
}
c++;
}
}
for (int i = 0; i < q; i++) {
string name1, ip1, pri1;
cin >> name1 >> ip1 >> pri1;
bool b = 0;
for (int j = 0; j < c; j++) {
if (a[j].name == name1 && a[j].ip == ip1) {
bool b1 = 0;
for (int k = 0; k < a[j].ge1; k++) {
if (mp[pri1] == a[j].ss[k]) {
cout << "Yes" << '\n';
b1 = 1;
break;
}
}
if (b1==0) {
cout << "No" << '\n';
}
b = 1;
break;
}
}
if (b==0) {
cout << "No" << '\n';
}
}
return 0;
}