NOIP2015 pj

2023-03-08,

达成成就!——尝试不看题解的情况下用cpp打完了一套NOIP pj

题目全部在luogu上——

P2669 金币

题目描述

国王将金币作为工资,发放给忠诚的骑士。第一天,骑士收到一枚金币;之后两天(第二天和第三天),每天收到两枚金币;之后三天(第四、五、六天),每天收到三枚金币;之后四天(第七、八、九、十天),每天收到四枚金币……;这种工资发放模式会一直这样延续下去:当连续N天每天收到N枚金币后,骑士会在之后的连续N+1天里,每天收到N+1枚金币。

请计算在前K天里,骑士一共获得了多少金币。

输入输出格式

输入格式:

输入文件只有1行,包含一个正整数K,表示发放金币的天数。

输出格式:

输出文件只有1行,包含一个正整数,即骑士收到的金币数。

输入输出样例

输入样例#1:

6

输出样例#1:

14

输入样例#2:

1000

输出样例#2:

29820

说明

【输入输出样例 1 说明】

骑士第一天收到一枚金币;第二天和第三天,每天收到两枚金币;第四、五、六天,

每天收到三枚金币。因此一共收到 1+2+2+3+3+3=14 枚金币。

对于 100%的数据, 1 ≤ K ≤ 10,000。

Solution

直接模拟

 1 #include<cstdio>
2 using namespace std;
3
4 int main(){
5 //freopen("1.in","r",stdin);
6 //freopen("1.out","w",stdout);
7
8 int n;
9 int i=0;
10 int ans=0;
11
12 scanf("%d",&n);
13
14 while (n>0)
15 {
16 n-=++i;
17 ans=ans+i*i;
18 }
19
20 ans=ans-(0-n)*i;
21 printf("%d",ans);
22
23 fclose(stdin); fclose(stdout);
24 return 0;
25 }

P2670 扫雷游戏

题目描述

扫雷游戏是一款十分经典的单机小游戏。在n行m列的雷区中有一些格子含有地雷(称之为地雷格),其他格子不含地雷(称之为非地雷格)。玩家翻开一个非地雷格时,该格将会出现一个数字——提示周围格子中有多少个是地雷格。游戏的目标是在不翻出任何地雷格的条件下,找出所有的非地雷格。

现在给出n行m列的雷区中的地雷分布,要求计算出每个非地雷格周围的地雷格数。

注:一个格子的周围格子包括其上、下、左、右、左上、右上、左下、右下八个方向上与之直接相邻的格子。

输入输出格式

输入格式:

输入文件第一行是用一个空格隔开的两个整数n和m,分别表示雷区的行数和列数。

接下来n行,每行m个字符,描述了雷区中的地雷分布情况。字符’*’表示相应格子是地雷格,字符’?’表示相应格子是非地雷格。相邻字符之间无分隔符。

输出格式:

输出文件包含n行,每行m个字符,描述整个雷区。用’*’表示地雷格,用周围的地雷个数表示非地雷格。相邻字符之间无分隔符。

输入输出样例

输入样例#1:

3 3
*??
???
?*?

输出样例#1:

*10
221
1*1

输入样例#2:

2 3
?*?
*??

输出样例#2:

2*1
*21

说明

对于 100%的数据, 1≤n≤100, 1≤m≤100。

Solution

还是模拟。。。

 1 #include<cstdio>
2 #include<cstring>
3 using namespace std;
4 int main(){
5 char c[100][100];
6 int apple[102][102];
7 memset(apple,0,sizeof(apple));
8 freopen("1.in","r",stdin);
9 freopen("1.out","w",stdout);
10
11 int n,m;
12 scanf("%d %d\n",&n,&m);
13
14 for (int i=1;i<=n;i++){
15 for (int j=1;j<=m;j++)
16 {
17 scanf("%c",&c[i][j]);
18 if (c[i][j]=='*'){
19 apple[i-1][j-1]++;
20 apple[i+1][j+1]++;
21 apple[i][j-1]++;
22 apple[i-1][j]++;
23 apple[i][j+1]++;
24 apple[i+1][j]++;
25 apple[i-1][j+1]++;
26 apple[i+1][j-1]++;
27 }
28 }
29 scanf("\n");
30 }
31 for (int i=1;i<=n;i++)
32 {
33 for (int j=1; j<=m;j++){
34 if (c[i][j]=='?') printf("%d",apple[i][j]);
35 else printf("*");
36 }
37 printf("\n");
38 }
39
40 }

P2671 求和

题目描述

一条狭长的纸带被均匀划分出了n个格子,格子编号从1到n。每个格子上都染了一种颜色color_i用[1,m]当中的一个整数表示),并且写了一个数字number_i。

定义一种特殊的三元组:(x,y,z),其中x,y,z都代表纸带上格子的编号,这里的三元

组要求满足以下两个条件:

1.xyz是整数,x<y<z,y-x=z-y

2.colorx=colorz

满足上述条件的三元组的分数规定为(x+z)*(number_x+number_z。整个纸带的分数

规定为所有满足条件的三元组的分数的和。这个分数可能会很大,你只要输出整个纸带的分数除以10,007所得的余数即可。

输入输出格式

输入格式:

第一行是用一个空格隔开的两个正整数n和m,n表纸带上格子的个数,m表纸带上颜色的种类数。

第二行有n用空格隔开的正整数,第i数字number表纸带上编号为i格子上面写的数字。

第三行有n用空格隔开的正整数,第i数字color表纸带上编号为i格子染的颜色。

输出格式:

共一行,一个整数,表示所求的纸带分数除以10,007所得的余数。

输入输出样例

输入样例#1:

6 2
5 5 3 2 2 2
2 2 1 1 2 1

输出样例#1:

82

输入样例#2:

15 4
5 10 8 2 2 2 9 9 7 7 5 6 4 2 4
2 2 3 3 4 3 3 2 4 4 4 4 1 1 1

输出样例#2:

1388

说明

【输入输出样例 1 说明】

纸带如题目描述中的图所示。

所有满足条件的三元组为: (1, 3, 5), (4, 5, 6)。

所以纸带的分数为(1 + 5)*(5 + 2) + (4 + 6)*(2 + 2) = 42 + 40 = 82。

对于第 1 组至第 2 组数据, 1 ≤ n ≤ 100, 1 ≤ m ≤ 5;

对于第 3 组至第 4 组数据, 1 ≤ n ≤ 3000, 1 ≤ m ≤ 100;

对于第 5 组至第 6 组数据, 1 ≤ n ≤ 100000, 1 ≤ m ≤ 100000,且不存在出现次数

超过 20 的颜色;

对 于 全 部 10 组 数 据 , 1 ≤ n ≤ 100000, 1 ≤ m ≤ 100000, 1 ≤ color_i ≤ m,1≤number_i≤100000

Solution

先按颜色排序,把同颜色的归为一类,然后根据奇偶性瞎搞就可以了,取模打错了好多次。。。

 1 #include<cstdio>
2 #include<cstring>
3 #include<algorithm>
4 using namespace std;
5
6 long long n,m;
7 long long color[100001],num[100001],id[100001];
8 const long long moding=10007;
9
10 void swap(long long &aa,long long &bb){ //swap function
11 long long tt;
12 tt=aa;
13 aa=bb;
14 bb=tt;
15 }
16
17 void qsort(long long l,long long r){
18 long long i=l,j=r,mi=id[(l+r)/2];
19 long long mm=color[(l+r)/2];
20
21 do
22 {
23 while ((color[i]<mm)||(color[i]==mm&&id[i]<mi)) i++;
24 while ((color[j]>mm)||(color[j]==mm&&mi<id[j])) j--; //double keys qsort
25 if (i<=j){
26 swap(color[i],color[j]);
27 swap(num[i],num[j]);
28 swap(id[i],id[j]);
29 i++;j--;
30 }
31 }while (i<=j);
32
33 if (l<j) qsort(l,j);
34 if (i<r) qsort(i,r);
35 }
36
37 int partit(long long l,long long r){
38 // long long odd_num[100001],no_num[100001];
39 // long long odd_color[100001],no_color[100001];
40 long long odd=0,no=0,odd_sum=0,no_sum=0,tmp=0;
41
42 for (long long j=l;j<=r;j++)
43 if (id[j]%2==1) {
44 odd++;
45 odd_sum+=id[j];
46 // odd_num[odd]=num[j]; odd_color[odd]=color[j];
47 }
48 else {
49 no++;
50 no_sum+=id[j];
51 // no_num[no]=num[j]; no_color[no]=color[j];
52 }
53 for (long long j=l;j<=r;j++)
54 if (id[j]%2==1) {
55 if (odd>1) tmp=((tmp % moding)+(num[j]*(odd_sum+id[j]*(odd-2)))%moding)%moding;
56 // printf("%lld \n",tmp); printf("----\n");
57 }
58 else if (no>1) tmp=((tmp % moding)+(num[j]*(no_sum+id[j]*(no-2)))%moding)%moding;
59 // printf("%lld \n",tmp); printf("======\n");
60 return tmp % moding;
61 }
62 int main(){
63 long long ll=1,ans=0;
64
65 freopen("sum.in","r",stdin);
66 freopen("sum.out","w",stdout);
67
68 scanf("%lld %lld\n",&n,&m);
69 for (long long i=1;i<=n;i++) scanf("%lld ",&num[i]);
70 for (long long i=1;i<=n;i++) scanf("%lld ",&color[i]);
71 for (long long i=1;i<=n;i++) id[i]=i;
72
73 qsort(1,n);
74
75 for (long long i=2;i<=n+1;i++)
76 if (color[i]!=color[i-1])
77 {
78 ans=((ans % moding)+partit(ll,i-1))%moding;
79 ll=i;
80 }
81 printf("%lld",ans);
82 return 0;
83 }

P2672 推销员

题目描述

阿明是一名推销员,他奉命到螺丝街推销他们公司的产品。螺丝街是一条死胡同,出口与入口是同一个,街道的一侧是围墙,另一侧是住户。螺丝街一共有N家住户,第i家住户到入口的距离为Si米。由于同一栋房子里可以有多家住户,所以可能有多家住户与入口的距离相等。阿明会从入口进入,依次向螺丝街的X家住户推销产品,然后再原路走出去。

阿明每走1米就会积累1点疲劳值,向第i家住户推销产品会积累Ai点疲劳值。阿明是工作狂,他想知道,对于不同的X,在不走多余的路的前提下,他最多可以积累多少点疲劳值。

输入输出格式

输入格式:

第一行有一个正整数N,表示螺丝街住户的数量。

接下来的一行有N个正整数,其中第i个整数Si表示第i家住户到入口的距离。数据保证S1≤S2≤…≤Sn<10^8。

接下来的一行有N个正整数,其中第i个整数Ai表示向第i户住户推销产品会积累的疲劳值。数据保证Ai<10^3。

输出格式:

输出N行,每行一个正整数,第i行整数表示当X=i时,阿明最多积累的疲劳值。

输入输出样例

输入样例#1:

5
1 2 3 4 5
1 2 3 4 5

输出样例#1:

15
19
22
24
25

输入样例#2:

5
1 2 2 4 5
5 4 3 4 1

输出样例#2:

12
17
21
24
27

说明

【输入输出样例1说明】

X=1:向住户5推销,往返走路的疲劳值为5+5,推销的疲劳值为5,总疲劳值为15。

X=2:向住户4、5推销,往返走路的疲劳值为5+5,推销的疲劳值为4+5,总疲劳值为5+5+4+5=19。

X=3:向住户3、4、5推销,往返走路的疲劳值为5+5,推销的疲劳值3+4+5,总疲劳值为5+5+3+4+5=22。

X=4:向住户2、3、4、5推销,往返走路的疲劳值为5+5,推销的疲劳值2+3+4+5,总疲劳值5+5+2+3+4+5=24。

X=5:向住户1、2、3、4、5推销,往返走路的疲劳值为5+5,推销的疲劳值1+2+3+4+5,总疲劳值5+5+1+2+3+4+5=25。

【输入输出样例2说明】

X=1:向住户4推销,往返走路的疲劳值为4+4,推销的疲劳值为4,总疲劳值4+4+4=12。

X=2:向住户1、4推销,往返走路的疲劳值为4+4,推销的疲劳值为5+4,总疲劳值4+4+5+4=17。

X=3:向住户1、2、4推销,往返走路的疲劳值为4+4,推销的疲劳值为5+4+4,总疲劳值4+4+5+4+4=21。

X=4:向住户1、2、3、4推销,往返走路的疲劳值为4+4,推销的疲劳值为5+4+3+4,总疲劳值4+4+5+4+3+4=24。或者向住户1、2、4、5推销,往返走路的疲劳值为5+5,推销的疲劳值为5+4+4+1,总疲劳值5+5+5+4+4+1=24。

X=5:向住户1、2、3、4、5推销,往返走路的疲劳值为5+5,推销的疲劳值为5+4+3+4+1,

总疲劳值5+5+5+4+3+4+1=27。

【数据说明】

对于20%的数据,1≤N≤20;

对于40%的数据,1≤N≤100;

对于60%的数据,1≤N≤1000;

对于100%的数据,1≤N≤100000。

Solution

刚开始测了一下二维的暴力只拿了40;

于是开始各种奇怪的东西,=>

首先我们可以发现在找x个买家时,我们可以从x-1的推过来,于是很明显的阶段性,决策有已经走了的和后面的,这里来个堆维护最大值就可以了,

但是我作死维护了两棵线段树。。。。。

然后还学会了gdb。。。。

  1 #include<cstdio>
2 #include<algorithm>
3 #include<cstring>
4 #define ll long long
5 #define pr(a) for(long long i=1;i<=n;i++) printf("%lld ",a[i]);printf("\n");
6 const ll maxn=100000+2;
7 using namespace std;
8
9
10 typedef struct {
11 ll val,left,right;
12 }arr;
13
14 //define var =====================
15
16 ll n,ap;
17 arr tree[4*maxn-1],tree2[4*maxn-1];
18 ll dis[maxn],tir[maxn],diss[maxn];
19 bool check[maxn];
20
21 //main codes =====================
22
23 void swap(long long &aa,long long &bb){ //swap function
24 long long tt;
25 tt=aa;
26 aa=bb;
27 bb=tt;
28 }
29
30 void qsort(long long l,long long r){
31 long long i=l,j=r;
32 long long mm=dis[(l+r)/2];
33
34 do
35 {
36 while (dis[i]<mm) i++;
37 while (dis[j]>mm) j--; //double keys qsort
38 if (i<=j){
39 swap(dis[i],dis[j]);
40 swap(tir[i],tir[j]);
41 i++;j--;
42 }
43 }while (i<=j);
44
45 if (l<j) qsort(l,j);
46 if (i<r) qsort(i,r);
47 }
48
49
50 void init(){
51 //freopen("1.in","r",stdin);
52 // freopen("1.out","w",stdout);
53
54 memset(check,1,sizeof(check));
55 scanf("%lld",&n);
56
57 for (ll i=1;i<=n;i++) scanf("%lld ",&dis[i]);
58 for (ll i=1;i<=n;i++) scanf("%lld ",&tir[i]);
59
60 tir[0]=0; dis[0]=0;
61 qsort(1,n);
62 }
63
64 void build( ll l , ll r , ll w){
65
66 tree[w].left=l; tree[w].right=r;
67 ll mid=(l+r)/2;
68
69 if (l==r) {
70 tree[w].val=l;
71 return;
72 }
73
74 build(l,mid,2*w);
75
76 build(mid+1,r,2*w+1);
77
78 if (dis[tree[2*w].val]>dis[tree[2*w+1].val])
79 tree[w].val= tree[2*w].val;
80 else
81 tree[w].val= tree[2*w+1].val;
82
83 }
84
85 ll query( ll l , ll r , ll w){
86
87 if (l<=tree[w].left&&tree[w].right<=r) return tree[w].val;
88
89 ll t1=0,t2=0;
90
91 if (l<=tree[2*w].right) t1=query(l,r,2*w);
92 if (tree[2*w+1].left<=r) t2=query(l,r,2*w+1);
93 if (dis[t1]>dis[t2]) return t1;
94 if (dis[t1]==dis[t2]) return min(t1,t2);
95 else return t2;
96 }
97
98
99
100 void build2( ll l , ll r , ll w){
101
102 tree2[w].left=l; tree2[w].right=r;
103 ll mid=(l+r)/2;
104
105 if (l==r) {
106 tree2[w].val=l;
107 return;
108 }
109
110 build2(l,mid,2*w);
111
112 build2(mid+1,r,2*w+1);
113
114 if (tir[tree2[2*w].val]>tir[tree2[2*w+1].val])
115 tree2[w].val= tree2[2*w].val;
116 else
117 tree2[w].val= tree2[2*w+1].val;
118
119 }
120
121 ll query2( ll l , ll r , ll w){
122
123 if (l<=tree2[w].left&&tree2[w].right<=r) return tree2[w].val;
124
125 ll t1=0,t2=0;
126
127 if (l<=tree2[2*w].right) t1=query2(l,r,2*w);
128 if (tree2[2*w+1].left<=r) t2=query2(l,r,2*w+1);
129
130 if (tir[t1]>tir[t2]) return t1;
131 if (tir[t1]==tir[t2]) return min(t1,t2);
132 else return t2;
133 }
134
135 void update2( ll x, ll w){
136
137 if (x==tree2[w].left&&x==tree2[w].right) {
138 tree2[w].val=0;
139 return;
140 }
141 if (x<=tree2[2*w].right) update2(x,2*w);
142 else update2(x,2*w+1);
143
144 if (tir[tree2[2*w].val]>tir[tree2[2*w+1].val])
145 tree2[w].val= tree2[2*w].val;
146 else
147 tree2[w].val= tree2[2*w+1].val;
148 }
149 void update( ll x, ll w){
150
151 if (x==tree[w].left&&x==tree[w].right) {
152 tree[w].val=0;
153 return;
154 }
155 if (x<=tree[2*w].right) update(x,2*w);
156 else update(x,2*w+1);
157
158 if (dis[tree[2*w].val]>dis[tree[2*w+1].val])
159 tree[w].val= tree[2*w].val;
160 else
161 tree[w].val= tree[2*w+1].val;
162 }
163
164 int main(){
165
166 init();
167
168 memcpy(diss,dis,sizeof(dis));
169 for (ll i=1;i<=n;i++)
170 dis[i]=dis[i]*2+tir[i];
171 build(1,n,1);
172 build2(1,n,1);
173
174 ll last=query(1,n,1),php1,php2;
175 ll ans=dis[last];
176 update(last,1);
177 update2(last,1);
178 // printf("last=%lld ans=%lld\n",last,ans);
179 printf("%lld\n",ans);
180 for (ll i=2;i<=n;i++)
181 {
182 ap=i;
183 php1=query2(1,last-1,1);
184 if (last+1<=n)php2=query(last+1,n,1); else php2=0;
185 // printf("%lld %lld \n",dis[php2],last);
186 if (tir[php1]>dis[php2]-diss[last]*2) {
187 ans+=tir[php1];
188 update2(php1,1);update(php1,1);
189 }
190 else {
191 ans+=dis[php2]-diss[last]*2;
192 last=php2;
193 update(php2,1);
194 update2(php2,1);
195 }
196 // printf("last=%lld ans=%lld\n",last,ans);
197 printf("%lld\n",ans);
198 }
199 // printf("%lld \n",tir[0]);
200 return 0;
201
202 }

NOIP2015 pj的相关教程结束。

《NOIP2015 pj.doc》

下载本文的Word格式文档,以方便收藏与打印。