前言:
蒟蒻尹:啊啊啊~~要疯啦!
为了不让我们玩得太high,我们的教练给我们布置了30题的AtCoder经典题当作业,还要写10篇题解。。。
可事实上。。。教练我们还有寒假作业啊 QAQ 555~~
这次我选了五道题来做讲解,后面会再出五道题;
这次讲解为了方便理解,我把一些题面改得通俗了一点,有的原题实在看不下去
好了废话不多说,开始奋斗吧>o<
第一题:おいしいたこ焼きの売り方 - 洛谷
题目描述:
高桥烦恼着怎样按顺序卖章鱼烧。因为知道做了的章鱼烧不好吃,所以高桥不想卖那样的章鱼烧,但是只卖刚做好的话,卖的章鱼烧的数量减少了。 另外,高桥君认为,光让客人等的话,客人会逐渐离开的。 于是,他就把在T秒内制作的章鱼烧继续卖下去,就决定调查客人是否能卖掉。 章鱼烧是A1、A2、…、AN秒后开始烤。 客人是B1、B2、…、在BM秒后来。 对于一个客人,卖一个章鱼烧。如果所有的客人都卖章鱼烧的话,请输出yes,如果卖不出去的话,请输出no。
输入输出格式
输入格式:
第一行输入一个 TT 代表章鱼烧的保质期,也就是说章鱼烧放置的超过 t秒就算过期,不能卖了。
第二行输入一个 nn 代表章鱼烧的数量。
第三行输入从 到
的 n个正整数,代表每个章鱼烧做出来的时间。
第四行输入一个 m 代表客人的数量。
第五行输入从 到
的 m 个正整数,表示每个客人来的时间。
输出格式:
如果所有的客人都会卖章鱼烧的话,请输出yes,如果卖不出去的话,请输出no。 另外,请在输出的末尾加入换行。
说明:
Sample Explanation 1
-每一个客人都买了一秒前做成的章鱼烧,可以给所有的客人卖章鱼烧。
Sample Explanation 2
-不能卖给最后的客人章鱼烧。
Sample Explanation 3
-高桥君的章鱼烧店很受欢迎。
Sample Explanation 4
-让第三位客人久等了。
输入输出样例:
样例1
输入:
1
3
1 2 3
3
2 3 4
输出:
yes
样例2
输入:
1
3
1 2 3
3
2 3 5
输出:
no
思路:
这道题我们可以暴力枚举。
Code:
#include<bits/stdc++.h>
using namespace std;
int t,n,m,h;
int a[100001],b[100001],k=1;
int main() {
scanf("%d",&t);
scanf("%d",&n);
for(int i=1; i<=n; i++)
scanf("%d",&a[i]);
sort(a+1,a+n+1);//排序
scanf("%d",&m);
for(int i=1; i<=m; i++)
scanf("%d",&b[i]);
sort(b+1,b+m+1);//排序
for(int i=1; i<=m; i++) {
for(int j=k; j<=n; j++) {
if(a[j]+t>=b[i]&&a[j]<=b[i]) {
//如果在第j个章鱼烧过期之前第i个客人还愿意等下去 而且 第j个章鱼烧的制作时间不长于第i个客人的耐心
k++;//下次循环从k+1开始,代表第k个章鱼烧买走了;
h++;//卖出的个数加1;
break;
}
}
}
if(h==m)
printf("yes\n");
else printf("no\n");
return 0;
}
第二题:3Match - 洛谷
题目描述
有 H行 W列的矩阵,每一个矩阵都有一个数字填充。我们需要找出连续的横着 3 个及以上或竖着 3个及以上的,由同一数字构成的长方形,如图:
但是,这有可能会连通。那么,这些连通的只会变成一个。如图:
需要求出长方形的个数(连通的只算一个)
输入格式
第一行两个正整数 NN 和 MM。
第二行到第 N + 1N+1 行,每一行 MM 个由 00 到 99 的数,没有空格。
输出格式
一个正整数,表示长方形的个数(连通的只算一个)
输入输出样例
样例 1
输入:
3 5
12302
22202
23102
输出:
3
如下图,有 3个长方形。
样例 2
输入:
3 6
111234
231114
332332
输出:
1
如下图,由于连通,所以只输出 1个。
思路:
这道题用dfs,在做之前不妨用一个数组打上标记。
Code:
#include<bits/stdc++.h>
using namespace std;
int n,m,ans;
char a[1010][1010];
bool b[1010][1010];
void dfs(int x,int y,char ss) {
if (x<1||y<1||x>n||y>m||!b[x][y]||a[x][y]!=ss) return ;
//如果越界或权值不同,或没有真标记,返回
b[x][y]=0;//!!!一定要去掉标记!!!防止在爬到这个地方
dfs(x,y-1,ss);//向四个方向递归
dfs(x,y+1,ss);
dfs(x-1,y,ss);
dfs(x+1,y,ss);
}
int main() {
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
cin>>a[i][j];
for(int i=1; i<=n; i++)//先找出长方形,打上真标记
for(int j=1; j<=m; j++) {
if(a[i][j]==a[i][j+1]&&a[i][j]==a[i][j+2])
b[i][j]=b[i][j+1]=b[i][j+2]=1;
if(a[i][j]==a[i+1][j]&&a[i][j]==a[i+2][j])
b[i][j]=b[i+1][j]=b[i+2][j]=1;
}
for(int i=1; i<=n; i++)//循环查询,dfs 消除标记
for(int j=1; j<=m; j++)
if(b[i][j])
dfs(i,j,a[i][j]),ans++;
printf("%d\n",ans);
return 0;
}
第三题:[ABC132C] Divide the Problems - 洛谷
题目描述
高桥在竞争性编程中提出了 NN 个问题,问题编号为 1至 n,问题 i的难度表示为整数(越高难度越大)。
他通过选择整数 k将问题分为两类,如下所示:
- 对于 ARC,难度为 K 或更高的问题。
- 难度低于 K 的问题将是 ABC。
整数 KK 有多少种选择可以使 ARC 的问题数和 ABC 的问题数相同?
输入输出样例
样例1
输入:
6
9 1 4 4 6 7
输出:
2
样例2
输入:
14
99592 10342 29105 78532 83018 11639 92015 77204 30914 21912 34519 80835 100000 1
输出:
42685
思路:
这道题很具有迷惑性,第一眼看上去,要用模拟,可是模拟铁T啊,肿么办捏?其实这是一道智商题;常规模拟是过不了的因此要智取。这道题中的N必为偶数,所以我们可以排序,发现在到
之间的值都满足使 ARC 的问题数和 ABC 的问题数相同的条件,然后用
的权值减去
的权值就可以了,是不是非常的睿智捏?
Code:
#include<bits/stdc++.h>
using namespace std;
int n;
int a[100010];
int main() {
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
sort(a+1,a+1+n);
printf("%d\n",a[n/2+1]-a[n/2]);
return 0;
}
第四题[ABC131D] Megalomania - 洛谷:
题目描述
N 个任务,完成一个任务需要 秒,需要在
秒前内完成(可以压线完成,即完成的时间正好是
)。问是否能完成全部任务,如果能,输出 Yes ,否则输出 No 。
样例1:
输入:
3
334 1000
334 1000
334 1000
输出:
No
样例2:
输入:
30
384 8895
1725 9791
170 1024
4 11105
2 6
578 1815
702 3352
143 5141
1420 6980
24 1602
849 999
76 7586
85 5570
444 4991
719 11090
470 10708
1137 4547
455 9003
110 9901
15 8578
368 3692
104 1286
3 4
366 12143
7 6649
610 2374
152 7324
4 7042
292 11386
334 5720
输出:
Yes
思路:
此题可以开结构体,分为两个元素:需要的时间,和限制的时间;
Code:
#include<bits/stdc++.h>
using namespace std;
int n;
struct yin {
int a;//需要的时间
int b;//限制的时间
} k[200005];
bool cmp(yin x,yin y) { //因为yin是结构体,所以将yin这一类数据排序要写逻辑函数(可以理解为排序规则)
if(x.b==y.b)//若两数的“限制时间”相等,则按照“所需时间”升序排序
return x.a<y.a;
return x.b<y.b;//否则按“限制时间”升序排列
}
long long sum=0;
int main() {
scanf("%d",&n);
for(int i=1; i<=n; i++)
scanf("%d%d",&k[i].a,&k[i].b);
sort(k+1,k+1+n,cmp);//排序
for(int i=1;i<=n;i++) {
sum+=k[i].a;//sum是工作时间的累加
if(k[i].b<sum) {//若之前工作时间的累加和 大于 当前任务的限制时间,可以输出了
printf("No\n");
return 0;
}
}
printf("Yes\n");
return 0;
}
第五题:[AGC034B] ABC - 洛谷(你没看错,此题就叫ABC)
题目描述:
您将得到一个由 A,B 和 C 组成的字符串 s。
Snuke 希望在 s 上执行多次以下操作:
选择一个连续的 s 的子字符串,该字符串是 ABC
并将其替换为 BCA
。
找到最大可能的操作数。
样例1:
输入:
ABCABC
输出:
3
样例2:
输入:
ABCACCBABCBCAABCB
输出:
6
思路:
此题看上去只能暴力,我已开始也是这么做的(此代码特别好懂,我就不写注释了~偷懒):
#include<bits/stdc++.h>
using namespace std;
string ss;
int ans=0;
int len;
int main() {
cin>>ss;
len=ss.size();
while(1) {
bool flag=0;
for(int i=0; i<len-2; i++) {
if(ss[i]=='A'&&ss[i+1]=='B'&&ss[i+2]=='C') {
ss[i]='B';
ss[i+1]='C';
ss[i+2]='A';
ans++;
flag=1;
i=i+2;
}
}
if(flag==0)
break;
}
printf("%d\n",ans);
return 0;
}
为了防止TLE我还花20分钟做了优化,保险起见还开了O2,结果。。。
我。。。555~~
于是我们可以从题目入手:操作后将“ABC”变为“BCA”,我们可以发现,操作后"BC"两个字母还是连着的,而光有连续的"BC",两个字母是不够的,我们要提供可操作的“ABC”,主要还是要看“可供”操作的‘A’的个数。于是我们可以利用这些特性,写出一下的代码:
Code:
#include<bits/stdc++.h>
using namespace std;
string ss;
long long ans=0;
int len,tot=0;
int main() {
cin>>ss;
len=ss.size();//获取ss的长度
for(int i=0; i<len; i++) {
if(ss[i]=='A') tot++;//记录可以操作的'A'的个数
else if(ss[i]=='B') {//如果当前是'B'
if(i+1<ss.size()&&ss[i+1]=='C')//后面还有字符,而且下一个字符是'C'
ans+=tot,i++;//答案就加上可操作的'A'的个数,跳过后面一个'C'继续循环,以保证不会遍历到'C'
else//否则清空可用的'A'
tot=0;
} else//如果如果当前为'C'清空可操作'A'的个数
tot=0;
}
printf("%lld\n",ans);
return 0;
}
如果还是看不懂的话,大家可以结合一下样例2自行理解一下:
ABCACCBABCBCAABCB
循环过程:
i=0 tot=1 ans=0
i=2 tot=1 ans=1
i=3 tot=2 ans=1
i=4 tot=0 ans=1
i=5 tot=0 ans=1
i=6 tot=0 ans=1
i=7 tot=1 ans=1
i=9 tot=1 ans=2
i=11 tot=1 ans=3
i=12 tot=2 ans=3
i=13 tot=3 ans=3
i=15 tot=3 ans=6
i=16 tot=0 ans=6
后记:
这次真的是熬夜在写文章啊,代码写的不好,请多指教Orz~~