刷题记录

CFF真题

【 201909-2 】小明种苹果(续)

小明种苹果(续)

小明种苹果(续)2

思路

1.发生苹果掉落和疏果是两种不同的操作 发生苹果掉落(5 3) 疏果(5 -3)

2.一棵树可能出现多次苹果掉落的情况 比如:3 5 2 1(对于一棵树来说 有3个操作,原来有5个苹果,第一次掉落后还剩2个,第二次掉落后还剩1个)

3.当发生苹果掉落的苹果树的棵树大于等于3时才可能形成连续的三个苹果树

注意 a可能是10^6 所以采用long long

源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include <iostream>
#include <string.h>

using namespace std;

typedef long long ll;

int main()
{
//定义长整型
ll n;
cin>>n;

ll *appleDrop = new ll [n];
ll lostNum = 0,lostCon = 0,sum = 0;
//初始化掉落苹果数组
memset(appleDrop,0,n*sizeof(appleDrop));
//输出数组初始化情况
// for(int i=0;i<n;i++) cout<<appleDrop[i];
// cout<<endl;
for(ll i=0;i<n;i++){
// 第 i 棵苹果的操作
ll number;
cin >> number;
//这颗苹果树有多少苹果
ll apple;
cin >> apple;
number--;

while(number--){
//疏果或重新统计
ll lost;
cin >> lost;

if(lost <= 0){
//疏果
apple += lost;

}else{
//重新统计
if(apple > lost){
apple = lost;
appleDrop[i] = 1;

}
}
}//end of while
//总数
sum += apple;
//掉落数
if(appleDrop[i]) lostNum++;

}//end of for

// 掉落苹果数组情况
// for(int i=0;i<n;i++) cout<<appleDrop[i];
// cout<<endl;
//连续三颗苹果树掉落

for(int i=1;i<n-1;i++){
if(appleDrop[i-1]&&appleDrop[i]&&appleDrop[i+1]){
lostCon++;
}
}
//首尾特殊情况
if(appleDrop[n-2]&&appleDrop[n-1]&&appleDrop[0]) lostCon++;
if(appleDrop[n-1]&&appleDrop[1]&&appleDrop[0]) lostCon++;


cout<<sum<<" "<<lostNum<<" "<<lostCon;
delete []appleDrop;
return 0;
}

测试用例

4
4 74 -7 -12 -5
5 73 -8 -6 59 -4
5 76 -5 -10 60 -2
5 80 -6 -15 59 0

5
4 10 0 9 0
4 10 -2 7 0
2 10 0
4 10 -3 5 0
4 10 -1 8 0

3
3 10 2 1
2 10 -5
3 10 3 1

小明种苹果(续)3

【201909-4】 推荐系统

推荐系统

思路

C++常用数据结构–STL ,照搬大佬的

使用map<int,set<pair<int,int> > > F保存所有数据,格式为map<Score,set<pair<Type,Commodity> > >
这样在容器内部首先会按Score排序,同一Score的先按Type排序,再按Commodity排序。
使用unordered_map<int,int>[50]保存编号到成绩的映射,格式为
unordered_map<Commodity,Score> G[Type]
这样指定Type和Commodity可以在F中迅速定位,从F中增删商品的时间度为O(log(Score的种数) * log(该分数的物品数))。

基础知识

map<class T1,class T2>特性:存储T1->T2映射的键值对,map先按照T1升序排序,再按T2升序排序,其中T1,T2可以是任意类(如:int、string、char或自定义类),T1值唯一,其插入删除的时间复杂度为O(log2)
unordered_map<class T1,class T2>特性:仅存储T1->T2映射的键值对,T1值唯一,其插入和删除的时间复杂度为O(1)

源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#include <iostream>
#include <string.h>
#include <set>
#include <map>
#include <vector>
#include <tr1/unordered_map>

using namespace std::tr1;
using namespace std;

typedef long long ll;


int main()
{

//总商品种类 n
ll n;
//商品类别 m
int m;
//操作数
ll op;
//查询次数
int opAsk;
//存储编号到分数的映射 ,map<commodity,score> g[Type]
unordered_map<ll,ll> g[51];
unordered_map<ll,ll>::iterator itG;
//存放商品信息 ,map<score,set<pair<Type,Commodity>>>
map<ll,set<pair<int,ll> > > pro;
map< ll,set< pair<int,ll> > >::iterator itP;
//分数,编号
ll score,commodity;
//种类
int type;

cin>>m>>n;

for(int i = 0; i < n; i++){
cin>>commodity>>score;
for(int j = 0; j < m; j++){
pro[score].insert(pair<int,ll>(j,commodity));
g[j][commodity] = score;
}

}

cin>>op;
opAsk = 0;

while(op--){

int opType;
cin>>opType;

switch(opType){

//添加
case 1:{
cin>>type>>commodity>>score;
g[type][commodity] = score;
pro[score].insert(pair<int,ll>(type,commodity));
break;
}

//删除
case 2:{
cin>>type>>commodity;
//若商品存在 则删除
if((itG = g[type].find(commodity)) != g[type].end()){
//找到该分数的容器
itP = pro.find(itG->second);
//删除该容器内指定商品
itP->second.erase(pair<int,ll>(type,commodity));
//若该分数下无商品,则删除该分数的容器
if(itP->second.empty()) pro.erase(itP);
//删除对应映射
g[type].erase(itG);
}
break;
}

//查询
case 3:{
opAsk++;
//总数 k
int k;
cin>>k;
//每类最大选出个数
ll Cout[m];
for(int i = 0; i < m; i++){
cin>>Cout[i];
}

//查询K类 ,不能使用set 因为set将自动排序,该题有bug
//set<ll> queryP[51];
//每类选择的编号
vector<ll> queryP[51];
// 按分数由大到小选择前k个物品
for(auto it = pro.rbegin(); it != pro.rend() && k>0; ++it){
set<pair<int,ll> >&s = it -> second;
for(auto itS = s.begin(); itS != s.end()&&k>0; ++itS){
const pair<int,ll>&p = *itS;
if(Cout[p.first] > 0){
//queryP[p.first].insert(p.second),--queryCout[p.first],--k;
queryP[p.first].push_back(p.second),--Cout[p.first],--k;
}
}
}
//输出选择的所有物品
for(int j=0;j<m;++j){//对所有类输出选择的物品
if(queryP[j].empty())//该类没有选中任何物品
cout<<-1<<endl;
else{
k=0;//仅仅用于判断是否输出空格
for(auto it=queryP[j].begin();it!=queryP[j].end();++it,++k)
cout<<(k==0?"":" ")<<*it;
cout<<endl;
}
}

break;
}

}// end-switch
}// end-while


return 0;
}

测试用例

1
2
3
4
5
6
7
8
9
10
11
12
13
2 3
1 3
2 2
3 1
8
3 100 1 1
1 0 4 3
1 0 5 1
3 10 2 2
3 10 1 1
2 0 1
3 2 1 1
3 1 1 1

【 201903-1 】 小中大

小中大

注意点:

涉及到四舍五入,以及小数点位数

源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include<iostream>
#include<iomanip>

using namespace std;

typedef long long ll;

int main(){

ll max,min;
ll mid;
int n;
cin>>n;
ll *arr = new ll[n];
for(int i = 0; i < n; i++){
cin>>arr[i];
}

max = arr[0];
min = arr[n-1];

if(min > max){
ll t;
t = max;
max= min;
min = t;
}

if(n%2 == 0){
mid = arr[n/2-1] + arr[n/2];
if(mid%2 == 0){
cout<<max<<" " <<mid/2<<" "<<min;
}else{
cout<<max<<" " <<fixed<< setprecision(1)<<mid*0.5<<" "<<min;
}

}else{
mid = arr[n/2];
cout<<max<<" " <<mid<<" "<<min;
}

return 0;
}

测试用例

1
2
3
4
5
6
7
8
4
-2 -1 3 4

4
-1 4 5 6

3
-1 2 4

【 201903-2 】 二十四点

二十四点

二十四点2

思路

方法一: 中缀表达式先构建表达树,后序遍历得到后缀表达式,然后计算结果

方法二:利用一个栈和一个字符串 得到后缀表达式,然后计算结果

参考 https://blog.csdn.net/fireflylane/article/details/83017889

将中缀表达式转换为后缀表达式
step1:初始化一个栈和一个后缀表达式字符串
step2:从左到右依次对中缀表达式中的每个字符进行以下处理,直到表达式结束

  • 如果字符是‘)’,将其入栈
  • 如果字符是数字,添加到s2中
  • 如果字符是运算符,先将栈顶优先级不低于该运算符的运算符出栈,添加到s2中,再将该运算符入栈。当‘)’在栈中是,优先级最低
    如果字符是‘(’,将栈顶元素出栈,添加到s2中,直到出栈的是‘)’

step3:如果表达式结束,但栈中还有元素,将所有元素出栈,添加s2中

step4:将栈s2中元素依次出栈,即得到前缀表达式

后缀表达式的计算
后缀表达式没有括号,运算符的顺序即为实际运算顺序,在求值过程中,当遇到运算符时,只要取得前两个操作数就可以立即进行计算。当操作数出现时,不能立即求值,需要先保存等待运算符。对于等待中的操作数而言,后出现的先运算,所以需要一个栈辅助操作。
后缀表达式的运算过程如下:
step1:设置一个栈
step2:从左到右对后缀表达式中的字符进行以下处理:

  • 如果字符是数字,现将其转化为数字,然后入栈
  • 如果字符是运算符,出栈两个值进行计算。计算结果入栈
  • 重复以上步骤,直到后缀表达式扫描结束,栈中最后一个元素就是表达式的结果。

方法三(比较巧妙,只适合本题没有括号的情况):提前考虑优先级 ,来源 https://blog.csdn.net/Dqmail/article/details/89318208

首先遍历表达式数组,当遇到x / 时 计算结果,例如 +AxB 算为 +0+(AxB)即: 原来的符号变成上一个符号,A位置变成0,B位置变成 A x B ,如果操作符在a[1],计算完后也需要改变为‘+’ ,最后再遍历一回数组依次相加减即可。

注意一点:首先是拿字符数组接收表达式,但如果直接拿字符相加减容易出问题,所以额外用整形数组保存数字。

源代码

方法一:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <iostream>
#include <string>

using namespace std;

string str;
const int maxn = 1000;
int lch[maxn], rch[maxn]; char op[maxn];
int nc = 0; //结点数
int build_tree(char* s, int x, int y)
{
int i, c1 = -1, c2 = -1, p = 0;
int u;
if(y-x == 1) //仅一个字符,建立单独结点
{
u = ++nc;
lch[u] = rch[u] = 0; op[u] = s[x];
return u;
}
for(i = x; i < y; i++)
{
switch(s[i])
{
case '(': p++; break;
case ')': p--; break;
case '+': case '-': if(!p) c1 = i; break;
case '*': case '/': if(!p) c2 = i; break;
}
}
if(c1 < 0) c1 = c2; //找不到括号外的加减号,就用乘除号
if(c1 < 0) return build_tree(s, x+1, y-1); //整个表达式被一对括号括起来
u = ++nc;
lch[u] = build_tree(s, x, c1);
rch[u] = build_tree(s, c1+1, y);
op[u] = s[c1];
return u;
}

int main()
{

cin>>str;
build_tree((char*)str.data(),0,str.length());
for(int i = 0; i < nc; i++ )
cout<<lch[i];
return 0;
}

方法二:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#include<iostream>
#include <string>
#include <stack>

using namespace std;

//定义运算符的优先级
int symPriority(char a){
if(a == 'x' || a == '/') return 2;
if(a == '+' || a == '-') return 1;
return 0;
}

//比较运算符的优先级
bool comparePriority(char a, char b){

int aValue = symPriority(a), bValue = symPriority(b);
if(aValue >= bValue) return true;
return false;
}

int main(){


int n ;
cin>>n;
while(n--){
//需要计算的中缀表达式
string expression;
cin>>expression;

//运算符栈,用于保存运算符
stack<char> opStack;
//后缀表达式
string symbol;

int el = expression.length();

for(int i = 0; i < el; i++){

//如果 ( 压入栈
if(expression[i] == '('){
opStack.push(expression[i]);
}
//数字 放入 后缀表达式
else if(expression[i] >= '0' && expression[i] <= '9'){
symbol.push_back(expression[i]);
}
// ) 弹出栈顶元素,直至出栈是的 (
else if(expression[i] == ')'){
while(!opStack.empty() &&opStack.top() != '('){
symbol.push_back(opStack.top());
opStack.pop();
}
if(opStack.top() == '(') opStack.pop();
}
// 若是其他运算符
else{
//先将栈顶优先级不低于该运算符的运算符出栈,
while(!opStack.empty() && comparePriority(opStack.top(),expression[i])){
symbol.push_back(opStack.top());
opStack.pop();
}
//再压入栈
opStack.push(expression[i]);
}
} // end of for

while(!opStack.empty()){
symbol.push_back(opStack.top());
opStack.pop();
}

//cout<<symbol<<endl;

/*
表达式的计算
*/

int sl = symbol.length();
stack<int> op;
for(int i = 0; i < sl; i++){
if( symbol[i]>= '0' && symbol[i] <= '9'){
op.push( symbol[i]-'0');
}else{
int a = op.top();
op.pop();
int b = op.top();
op.pop();
switch(symbol[i]){
case '+': b+=a;op.push(b);break;
case '-': b-=a;op.push(b);break;
case 'x': b*=a;op.push(b);break;
case '/': b/=a;op.push(b);break;
}
}
}
// cout<<op.top()<<endl;
//判断是否等于24点
if(op.top() == 24){
cout<<"Yes"<<endl;
}else{
cout<<"No"<<endl;
}
}
return 0;
}

方法三:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include<iostream>

using namespace std;

int main(){


int n ;
cin>>n;
while(n--){
//输入表达式
char a[8];
int b[7];
cin>>a;

for(int i = 0; i < 8; i+=2) b[i] = a[i]-'0';

for(int i = 1; i < 7; i+=2){
//遍历一遍 x /
if(a[i] == 'x'){
b[i+1] *= b[i-1];
b[i-1] = 0;

if(i == 3 || i == 5 ) a[i] = a[i-2];
if(i == 1) a[i] = '+';
}

if(a[i] == '/'){
b[i+1] = b[i-1] / b[i+1];
b[i-1] = 0;
if(i == 3 || i == 5 ) a[i] = a[i-2];
if(i == 1) a[i] = '+';
}
}

int sum = b[0];

//此时表达式只有+-,依次计算
for(int i = 1; i < 7; i+=2){

if(a[i] == '+'){
sum += b[i+1] ;
}

if(a[i] == '-'){
sum -= b[i+1] ;
}
}

//判断是否等于24点
if(sum == 24){
cout<<"Yes"<<endl;
}else{
cout<<"No"<<endl;
}

}// end of n

return 0;
}

测试用例

1
2
3
4
5
6
7
8
9
10
11
10
9+3+4x3
5+4x5x5
7-9-9+8
5x6/5x4
3+5+7+9
1x1+9-9
1x9-5/9
8/5+6x9
6x7-3x6
6x4+4/5

【 201812-2 】 小明放学

题目背景

  汉东省政法大学附属中学所在的光明区最近实施了名为“智慧光明”的智慧城市项目。具体到交通领域,通过“智慧光明”终端,可以看到光明区所有红绿灯此时此刻的状态。小明的学校也安装了“智慧光明”终端,小明想利用这个终端给出的信息,估算自己放学回到家的时间。

问题描述

  一次放学的时候,小明已经规划好了自己回家的路线,并且能够预测经过各个路段的时间。同时,小明通过学校里安装的“智慧光明”终端,看到了出发时刻路上经过的所有红绿灯的指示状态。请帮忙计算小明此次回家所需要的时间。

输入格式

  输入的第一行包含空格分隔的三个正整数 r、y、g,表示红绿灯的设置。这三个数均不超过 106。
 输入的第二行包含一个正整数 n,表示小明总共经过的道路段数和路过的红绿灯数目。
 接下来的 n 行,每行包含空格分隔的两个整数 k、t。k=0 表示经过了一段道路,将会耗时 t 秒,此处 t 不超过 106;k=1、2、3 时,分别表示出发时刻,此处的红绿灯状态是红灯、黄灯、绿灯,且倒计时显示牌上显示的数字是 t,此处 t 分别不会超过 r、y、g。

输出格式

  输出一个数字,表示此次小明放学回家所用的时间。

样例输入

30 3 30
8
0 10
1 5
0 11
2 2
0 6
0 3
3 10
0 3

样例输出

46

样例说明

  小明先经过第一段路,用时 10 秒。第一盏红绿灯出发时是红灯,还剩 5 秒;小明到达路口时,这个红绿灯已经变为绿灯,不用等待直接通过。接下来经过第二段路,用时 11 秒。第二盏红绿灯出发时是黄灯,还剩两秒;小明到达路口时,这个红绿灯已经变为红灯,还剩 11 秒。接下来经过第三、第四段路,用时 9 秒。第三盏红绿灯出发时是绿灯,还剩 10 秒;小明到达路口时,这个红绿灯已经变为红灯,还剩两秒。接下来经过最后一段路,用时 3 秒。共计 10+11+11+9+2+3 = 46 秒。

评测用例规模与约定

  有些测试点具有特殊的性质:
  前 2 个测试点中不存在任何信号灯。
 测试点的输入数据规模:  
前 6 个测试点保证 n ≤ 103。
 * 所有测试点保证 n ≤ 105。

源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#include <iostream>

using namespace std;

typedef long long ll;

int main(){

ll r,y,g;
int n;
ll sum = 0;

cin>>r>>y>>g;
cin>>n;

while(n--){
ll k,t,k2,t2;
cin>>k>>t;

switch(k){
case 0:
k2 = k;
t2 = t;
break;

//红灯
case 1:
if(sum < t){
k2 = 1;
t2 = t - sum;
}else if(sum>t && sum<t+g){
k2 = 3;
}else{
int x = (sum-t-g) % (r+y+g);
if(x<y){
k2 = 2;
t2 = y-x;
}else if(x>y && x< (y+r)){
k2 = 1;
t2 = y+r-x;
}else{
k2 = 3;
}
}
break;

//黄灯
case 2:
if(sum < (t+r)){
k2 = 1;
t2 = (t+r) - sum;
}else if(sum > (t+r) && sum < (t+r+g)){
k2 = 3;
}else{
int x = (sum-t-r-g) % (r+y+g);
if(x<y){
k2 = 2;
t2 = y-x;
}else if(x>y && x< (y+r)){
k2 = 1;
t2 = y+r-x;
}else{
k2 = 3;
}
}
break;

//绿灯
case 3:
if(sum < t || sum == t){
k2 = 3;
}else{
int x = (sum-t) % (r+y+g);
if(x<y){
k2 = 2;
t2 = y-x;
}else if(x>y && x< (y+r)){
k2 = 1;
t2 = y+r-x;
}else{
k2 = 3;
}
}
break;
}

switch(k2){
case 0:
sum += t2;
break;
case 1:
sum += t2;
break;
case 2:
sum += (t2+r);
break;
case 3:
break;
}

}
cout<<sum;
return 0;
}

【201803-2】碰撞的小球

问题描述

  数轴上有一条长度为L(L为偶数)的线段,左端点在原点,右端点在坐标L处。有n个不计体积的小球在线段上,开始时所有的小球都处在偶数坐标上,速度方向向右,速度大小为1单位长度每秒。
 当小球到达线段的端点(左端点或右端点)的时候,会立即向相反的方向移动,速度大小仍然为原来大小。
 当两个小球撞到一起的时候,两个小球会分别向与自己原来移动的方向相反的方向,以原来的速度大小继续移动。
 现在,告诉你线段的长度L,小球数量n,以及n个小球的初始位置,请你计算t秒之后,各个小球的位置。

提示

  因为所有小球的初始位置都为偶数,而且线段的长度为偶数,可以证明,不会有三个小球同时相撞,小球到达线段端点以及小球之间的碰撞时刻均为整数。
 同时也可以证明两个小球发生碰撞的位置一定是整数(但不一定是偶数)。

输入格式

  输入的第一行包含三个整数n, L, t,用空格分隔,分别表示小球的个数、线段长度和你需要计算t秒之后小球的位置。
 第二行包含n个整数a1, a2, …, an,用空格分隔,表示初始时刻n个小球的位置。

输出格式

  输出一行包含n个整数,用空格分隔,第i个整数代表初始时刻位于ai的小球,在t秒之后的位置。

样例输入

3 10 5
4 6 8

样例输出

7 9 9

注意点

碰撞之后转向,还要动。

两边都是墙壁。

源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <iostream>

using namespace std;

typedef struct node{
int number;
bool ori = 1;
bool noCrush = 1;
}node;

int main(){
int n,l,t;
cin>>n>>l>>t;

node *a = new node[n];
for(int i = 0; i < n; i++){
cin>>a[i].number;
}


while(t--){

for(int i = 0; i < n; i++){
//撞到墙壁
if(a[i].number == l){
a[i].ori = 0;
}else if(a[i].number == 0){
a[i].ori = 1;
}else{
//撞到其他小球
if(a[i].noCrush){
for(int j = 0; j < n; j++){
if(i != j && a[i].number == a[j].number){
a[i].noCrush = 0;
a[j].noCrush = 0;
break;
}
}// end of j
}
}

if(!a[i].noCrush){
a[i].ori = !a[i].ori;
a[i].noCrush = 1;
}

if(a[i].ori) a[i].number++;
else a[i].number--;

}// end of i

}

for(int i = 0; i < n; i++)
cout<<a[i].number<<" ";

delete []a;
return 0;
}

【201803-3】 URL映射

问题描述

  URL 映射是诸如 Django、Ruby on Rails 等网页框架 (web frameworks) 的一个重要组件。对于从浏览器发来的 HTTP 请求,URL 映射模块会解析请求中的 URL 地址,并将其分派给相应的处理代码。现在,请你来实现一个简单的 URL 映射功能。
 本题中 URL 映射功能的配置由若干条 URL 映射规则组成。当一个请求到达时,URL 映射功能会将请求中的 URL 地址按照配置的先后顺序逐一与这些规则进行匹配。当遇到第一条完全匹配的规则时,匹配成功,得到匹配的规则以及匹配的参数。若不能匹配任何一条规则,则匹配失败。
 本题输入的 URL 地址是以斜杠 / 作为分隔符的路径,保证以斜杠开头。其他合法字符还包括大小写英文字母、阿拉伯数字、减号 -、下划线 _ 和小数点 .。例如,/person/123/ 是一个合法的 URL 地址,而 /person/123? 则不合法(存在不合法的字符问号 ?)。另外,英文字母区分大小写,因此 /case/ 和 /CAse/ 是不同的 URL 地址。
 对于 URL 映射规则,同样是以斜杠开始。除了可以是正常的 URL 地址外,还可以包含参数,有以下 3 种:
 字符串 :用于匹配一段字符串,注意字符串里不能包含斜杠。例如,abcde0123。
 整数 :用于匹配一个不带符号的整数,全部由阿拉伯数字组成。例如,01234。
 路径 :用于匹配一段字符串,字符串可以包含斜杠。例如,abcd/0123/。
 以上 3 种参数都必须匹配非空的字符串。简便起见,题目规定规则中 前面一定是斜杠,后面要么是斜杠,要么是规则的结束(也就是该参数是规则的最后一部分)。而 的前面一定是斜杠,后面一定是规则的结束。无论是 URL 地址还是规则,都不会出现连续的斜杠。

输入格式

  输入第一行是两个正整数 nm,分别表示 URL 映射的规则条数和待处理的 URL 地址个数,中间用一个空格字符分隔。
 第 2 行至第 n+1 行按匹配的先后顺序描述 URL 映射规则的配置信息。第 i+1 行包含两个字符串 piri,其中 pi 表示 URL 匹配的规则,ri 表示这条 URL 匹配的名字。两个字符串都非空,且不包含空格字符,两者中间用一个空格字符分隔。
 第 n+2 行至第 n+m+1 行描述待处理的 URL 地址。第 n+1+i 行包含一个字符串 qi,表示待处理的 URL 地址,字符串中不包含空格字符。

输出格式

  输入共 m 行,第 i 行表示 qi 的匹配结果。如果匹配成功,设匹配了规则 pj ,则输出对应的 rj。同时,如果规则中有参数,则在同一行内依次输出匹配后的参数。注意整数参数输出时要把前导零去掉。相邻两项之间用一个空格字符分隔。如果匹配失败,则输出 404。

样例输入

5 4
/articles/2003/ special_case_2003
/articles// year_archive
/articles/// month_archive
/articles//// article_detail
/static/ static_serve
/articles/2004/
/articles/1985/09/aloha/
/articles/hello/
/static/js/jquery.js

样例输出

year_archive 2004
article_detail 1985 9 aloha
404
static_serve js/jquery.js

样例说明

  对于第 1 个地址 /articles/2004/,无法匹配第 1 条规则,可以匹配第 2 条规则,参数为 2004。
 对于第 2 个地址 /articles/1985/09/aloha/,只能匹配第 4 条规则,参数依次为 1985、9(已经去掉前导零)和 aloha。
 对于第 3 个地址 /articles/hello/,无法匹配任何一条规则。
 对于第 4 个地址 /static/js/jquery.js,可以匹配最后一条规则,参数为 js/jquery.js。

数据规模和约定

  1 ≤ n ≤ 100,1 ≤ m ≤ 100。
 所有输入行的长度不超过 100 个字符(不包含换行符)。
 保证输入的规则都是合法的。

思路

一组string的vector存放数据,用“/”分割每条语句。

依次拿规则来匹配url,别弄反了不然思路会有点乱,尤其是< path >规则。

注意事项有:规则的字符串分组必须与url的一样,即在< path >规则中 url后所有字符串为一个整体。还有前导零的去除

源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <ctype.h>
using namespace std;

typedef struct rule{
vector<string> p;
string r;
bool endflag;
}rule;

void split(vector<string> &v, char *s){
char *sp = strtok(s,"/");
while(sp){
v.push_back(sp);
//strtok()是非线程安全的
sp = strtok(NULL,"/");
}
}

//字符串全是数字
bool isint(string s){
for(int i = 0; i < s.length(); i++){
if(!isdigit(s[i])) {
return false;
}
}
return true;
}

//合法字符串
bool isLegal(string s){

for(int i = 0; i < s.length(); i++){
if(isdigit(s[i]) || isalpha(s[i]) || s[i]=='/'|| s[i]=='-'|| s[i]=='.'|| s[i]=='_'){
continue;
}else {
return false;
}
}
return true;
}

int main(){

int n,m;
cin>>n>>m;

rule *a = new rule[n];

for(int i = 0; i < n; i++){
string str;
//读取换行符,并舍弃
getline(cin,str,' ');
str = str.substr(1);
a[i].endflag = (str[str.length()-1] =='/')?0:1;
//cout<<"ru last: "<<str[str.length()-1]<<endl;
split(a[i].p,(char *)str.data());
cin>>a[i].r;

}
for(int i = 0; i < m; i++){
string str;
vector<string> url;
vector<string> ans;
//结尾中是否有/
bool flag;
//是否存在path
//bool pathflag = 0;
//分离字符串
cin>>str;
flag = (str[str.length()-1] =='/')?0:1;
//cout<<"url last: "<<str[str.length()-1]<<endl;
split(url,(char *)str.data());

//寻找匹配规则
int j;

for(j = 0; j < n; j++){
int ui = 0,pi = 0;
int ul = url.size();
int pl = a[j].p.size();
bool match = 1;

ans.clear();
while(match && ui < ul && pi < pl ){

if(!isLegal(url[ui])){
match = 0;
ans.clear();
break;
}

if(a[j].p[pi] == "<int>"){
if(isint(url[ui])){
int w;
//去除前导零
for(w=0;w<url[ui].size()-1&&url[ui][w]=='0';w++);
ans.push_back(url[ui].substr(w));
ui++;pi++;
}else{
match = 0;
}
}else if(a[j].p[pi] == "<path>"){
if(flag&&a[j].endflag){
//将后面的字符串看作一个整体
string ts;
while(ui<ul) ts = ts+"/"+url[ui++];
ans.push_back(ts.substr(1));
pi++;
/*pathflag = 1;
while(pathflag){
ans.push_back(url[ui]);
ui++;pi++;
if(ui < ul){
ans.push_back("/");
}
else break;
}*/
break;
}else{
match = 0;
}
}else if(a[j].p[pi] == "<str>" ){
ans.push_back(url[ui]);
ui++;pi++;
}
else if(a[j].p[pi] == url[ui]){
ui++;pi++;
}
else{
match = 0;
}
}//// end of match
//cout<<flag<<" "<<a[i].endflag;
if(match && (ui == ul) && (pi == pl)&& (flag==a[j].endflag)){
break;
break;
}else{
ans.clear();
}
}// end of j
if(j != n){
cout<<a[j].r;
for(int ansi = 0; ansi < ans.size();ansi++){
cout<<" "<<ans[ansi];
/*if(!pathflag){
if(ansi < ans.size()-1){
cout<<" ";
}
}*/
}
}else{
cout<<"404";
}
if(i != m-1) cout<<endl;
}// end of i


delete [] a;
return 0;
}

测试用例

1
2
3
4
5
6
7
8
9
10
11
5 10
/articles/2003/ special_case_2003
/articles/<int>/<int>/<str>/ article_detail
/articles/<str>/<int>/<str>/ le_detail
/static/<path> static_serve
/<str>/<path> serve
/articles/2004
/articles/2004/
/static/js/jquery.js
/static/js
/articles/1985/09/aloha/

过程太艰难了。

URL映射

他人满分代码

出处

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include<iostream>
#include<cstring>
#include<string>
#include<vector>

using namespace std;

const int N=105;

struct Rule{
vector<string>p;//URL匹配的规则
string r;//URL 匹配的名字
bool flag;//标记规则最后是否有"/"
}a[N];


//字符串分割函数,将字符串s用"/"分割,并存放于向量v中
void split(vector<string> &v,char *s)
{
char *sp=strtok(s,"/");
while(sp)
{
v.push_back(sp);
sp=strtok(NULL,"/");
}
}

//判断字符串s是否都是数字
bool isNum(string s)
{
for(int i=0;i<s.length();i++)
if(!isdigit(s[i]))
return false;
return true;
}

int n,m;//规则和查询的条数

//处理URL地址,flag标记此URL地址最后是否有"/"
void solve(vector<string>URL,bool flag)
{
int i;
vector<string>ans;//存放参数
for(i=0;i<n;i++)//顺序遍历n条规则
{
ans.clear();//先清空
int j=0,k=0;
vector<string>t(a[i].p);
while(j<t.size()&&k<URL.size())//查看URL是否和此规则匹配
{
if(t[j]=="<int>")//情况一:<int>
{
if(isNum(URL[k]))//如果都是数字
{
int w;
for(w=0;w<URL[k].size()-1&&URL[k][w]=='0';w++);//去前导零
ans.push_back(URL[k].substr(w));
j++,k++;//匹配下一部分
continue;
}
}
else if(t[j]=="<str>")//情况二:<str>
{
ans.push_back(URL[k]);//直接记录即可
j++,k++;//匹配下一部分
continue;
}
else if(t[j]=="<path>")//情况三: <path>
{
string s;
while(k<URL.size()) s=s+"/"+URL[k++];
ans.push_back(s.substr(1));//要去除第一个"/"符号
j++;
continue;
}
else if(t[j]==URL[k])
{
j++,k++;//匹配下一部分
continue;
}
break;
}
if(j==t.size()&&k==URL.size()&&flag==a[i].flag) break;//如果匹配就跳出
}
if(i==n)
cout<<"404"<<endl;//如果n条规则都匹配失败,则输出"404"
else
{
cout<<a[i].r;//输出匹配的规则的名字
for(int w=0;w<ans.size();w++)//输出各个参数
cout<<" "<<ans[w];
cout<<endl;
}
}

int main()
{
cin>>n>>m;
string rule;
for(int i=0;i<n;i++)
{
char temp[120];
scanf("%s",temp);
cin>>a[i].r;
a[i].flag=(temp[strlen(temp)-1]=='/')?true:false;//记录规则的最后是否有"/"
split(a[i].p,temp);//分割
}
for(int i=0;i<m;i++)
{
vector<string>URL;
char temp[120];
scanf("%s",temp);
bool flag=(temp[strlen(temp)-1]=='/')?true:false;//记录规则的最后是否有"/"
split(URL,temp);//分割
solve(URL,flag);//判断处理
}
return 0;
}

杭电OJ

大数相加

源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <iostream>
#include <string.h>
using namespace std;

void sum(char *a, char *b){
int c[1000] = {0}, t[1000] = {0};
int aL = strlen(a);
int bL = strlen(b);

if( aL >= bL ){
//游标
int i;
//两数位数差
int x = aL - bL;
for(i = bL-1; i > -1 ; i--){
//判断是否进位
c[i+x] = a[i+x]-'0' + b[i]-'0' + t[i+x+1];
if(c[i+x] > 9){
//标志前一位 需要加1(进位)
t[i+x] = 1;
c[i+x] -= 10;
}
}

i = x-1;
//a剩余位数直接赋值
for(; i > -1 ; i--){
c[i] = a[i]-'0' + t[i+1];
if(c[i] > 9){
//标志前一位 需要加1(进位)
t[i] = 1;
c[i] -= 10;
}
}
if(t[0]==1) c[0] += 10;

for(i = 0; i < aL; i++)
cout<<c[i];

// a<b
}else{
sum(b,a);
}

}

int main(){

int n,Case=0;
cin>>n;

while(n--){
char a[1000];
char b[1000];
cin>>a>>b;
Case++;
cout<<"Case "<<Case<<":"<<endl<<a<<" + "<<b<<" = ";
sum(a,b);
//最后一行不需要换两行。。
if(n == 0) cout<<endl;
else cout<<endl<<endl;
}
return 0;
}

测试数据

6组测试数据

6
99 1
Case 1:
99 + 1 = 100

888 744
Case 2:
888 + 744 = 1632

987654321987654321 987654321987654321
Case 3:
987654321987654321 + 987654321987654321 = 1975308643975308642

9999999999999999999 9
Case 4:
9999999999999999999 + 9 = 10000000000000000008

44 55
Case 5:
44 + 55 = 99

Case 6:

454546 4545499999999999999999999999999999

454546 + 4545499999999999999999999999999999 = 4545500000000000000000000000454545

递归转迭代(fi)

源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
#include <string.h>
using namespace std;

int main(){

int a,b,n;
while(cin>>a>>b>>n){
if(a == 0 || b == 0 || n == 0)
break;
if(n == 1)
cout<<1<<endl;
else if(n == 2)
cout<<1<<endl;
else{
int sum1 = 1 , sum2 = 1;
int sum = 0;
for(int i = 3; i <= n; i++){

sum = (a*sum2 + b*sum1) % 7;
sum1 = sum2;
sum2 = sum;
}
cout<<sum<<endl;
}
}
return 0;
}

字符串统计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include <iostream>
#include <string.h>
using namespace std;

int main(){

int n;
cin>>n;
//至0结束
while(n){
//记录各种颜色出现多少次
//int *Count = new int[n];
int Count[1000] = {0};
int index = 0;
//char (*p)[20] = new char[n][20];
char p[1000][20] = {};
bool flag = true;

for(int i=0; i<n; i++){
char str[20];
cin>>str;
//计数
if(i == 0){
strcpy(p[index],str);
Count[index]++;
index++;
}else{
int j;
for(j=0; j<index; j++){
if(strcmp(str,p[j]) == 0){
Count[j]++;
flag = false;
break;
}
}//end of for
//没有就添加进去
if(flag){
strcpy(p[index],str);
Count[index]++;
index++;
flag = true;
}

}//end of else
}

//找到最大值
int Cmax = Count[0],t=0;
for(int i = 1; i < index; i++ ){
if(Cmax < Count[i]){
Cmax = Count[i];
t = i;
}
}
cout<<p[t]<<endl;
//释放动态空间
// for(int i = 0; i < n; i++){
// delete []p[i];
// }
// delete []p;
cin>>n;
}
return 0;
}


/*
// template 模板
template<typename T>
//计算数组长度
int calculateLength(T &arr){
cout<<"size arr:"<<sizeof(arr)<<endl;
cout<<"size arr[0]:"<<sizeof(arr[0])<<endl;
return sizeof(arr) / sizeof(arr[0]);
}
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/* 2072 */
#include <iostream>
#include <string>

using namespace std;

int main(){

string ju;
string p[10001];

getline(cin,ju,'#');
int len = ju.length();

int index = 0;
string letter;
letter.clear();

for(int i = 0; i < len; i++){

if(ju[i]>='a' && ju[i]<='z'){
letter.push_back(ju[i]);
continue;
}

if(!letter.empty()){
if(index == 0){
p[index] = letter;
index++;
}else{
int j;
bool flag = true;
for(j = 0; j < index; j++){
if(letter == p[j]){
flag = false;
}
}//end of for

if(flag){
p[index] = letter;
index++;
}

}//end of inside if

letter.clear();
}

}// end of for

cout<<index;
return 0;
}

【1003】Max Sum

Problem Description

Given a sequence a[1],a[2],a[3]……a[n], your job is to calculate the max sum of a sub-sequence. For example, given (6,-1,5,4,-7), the max sum in this sequence is 6 + (-1) + 5 + 4 = 14.

Input

The first line of the input contains an integer T(1<=T<=20) which means the number of test cases. Then T lines follow, each line starts with a number N(1<=N<=100000), then N integers followed(all the integers are between -1000 and 1000).

Output

For each test case, you should output two lines. The first line is “Case #:”, # means the number of the test case. The second line contains three integers, the Max Sum in the sequence, the start position of the sub-sequence, the end position of the sub-sequence. If there are more than one result, output the first one. Output a blank line between two cases.

Sample Input

1
2
3
2
5 6 -1 5 4 -7
7 0 6 -1 1 -6 7 -5

Sample Output

1
2
3
4
5
Case 1:
14 1 4

Case 2:
7 1 6

题意

给定T组序列,找到各个序列中和最大值以及始点终点

思路

采用动态规划,简化版-》当sum加上a[i]比a[i]小,则结束记录;重新开始下一段和的计算。同时更新最大值以及始点终点。

源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <iostream>

using namespace std;

typedef long long ll;

int all[1000000] = {0};

int main(){

int t;
cin>>t;
for(int index = 1; index <= t; index++){

ll n;
cin>>n;

int* a = new int[n] ;

for(int i = 0; i < n; i++)
cin>>a[i];

int allMax,sum,startT,endT,f;
allMax = sum = -0xfffffff;

for(int i = 0; i < n; i++){
if((sum +a[i] > a[i]) ||(sum +a[i] == a[i])) {
sum += a[i];
}else{
sum = a[i];
f = i;
}

if(sum > allMax){
allMax = sum;
startT = f;
endT = i;
}
}

cout<<"Case " <<index<<":"<<endl;
cout<<allMax<<" "<<startT+1<<" "<<endT+1<<endl;
if(index != t){
cout<<endl;
}
}

return 0;
}

【1024】Max Sum Plus Plus

Problem Description

Now I think you have got an AC in Ignatius.L’s “Max Sum” problem. To be a brave ACMer, we always challenge ourselves to more difficult problems. Now you are faced with a more difficult problem.

Given a consecutive number sequence S1, S2, S3, S4 … Sx, … Sn (1 ≤ x ≤ n ≤ 1,000,000, -32768 ≤ Sx ≤ 32767). We define a function sum(i, j) = Si + … + Sj (1 ≤ i ≤ j ≤ n).

Now given an integer m (m > 0), your task is to find m pairs of i and j which make sum(i1, j1) + sum(i2, j2) + sum(i3, j3) + … + sum(im, jm) maximal (ix ≤ iy ≤ jx or ix ≤ jy ≤ jx is not allowed).

But I`m lazy, I don’t want to write a special-judge module, so you don’t have to output m pairs of i and j, just output the maximal summation of sum(ix, jx)(1 ≤ x ≤ m) instead. ^_^

Input

Each test case will begin with two integers m and n, followed by n integers S1, S2, S3 … Sn.
Process to the end of file.

Output

Output the maximal summation described above in one line.

Sample Input

1
2
1 3 1 2 3
2 6 -1 4 -2 3 -2 3

Sample Output

1
2
6
8

题意

n个序列分m组,求出最大m个字段的序列元素和

思路

源代码

1
2


---------------- 本文结束 ----------------

本文标题:刷题记录

文章作者:Pabebe

发布时间:2019年10月24日 - 17:53:37

最后更新:2021年04月05日 - 10:56:27

原始链接:https://pabebezz.github.io/article/fe644ae0/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

0%