文章目录
前言
我还记得,当年我也是一个平均学分绩点可以达到4的好学生。
现在博主已经变成了平均学分绩点在3~3.5徘徊的fw了,但主不在乎。
吐槽一下,夜王在权游里整整铺垫了3季还要多,又是异鬼军团又是转化冰龙,结果boss战里二丫只用了11秒就单杀了夜王。(从夜王拔剑开始,到二丫把刀刺进夜王身体,11s)
跟我预想中的boss战差了亿点点,不过还是很不错的。
下图为免疫龙焰的歪嘴屑夜王,一个明明可以猥琐在后面施法复活队友拿下胜利却有着上单的胆子冲到人家法师面前结果被敌方刺客11秒刀死的不死族法师。
A. Computer Game(思维+水题)
比赛链接:https://codeforces.com/contest/1598/problem/A
题目大意
M
o
n
o
c
a
r
p
Monocarp
Monocarp正在玩一款游戏,现在他进入了游戏的第一关。
这一关是一个
2
2
2行
n
n
n列的迷宫,迷宫里
0
0
0代表可以走,
1
1
1代表不可以走。
M
o
n
o
c
a
r
p
Monocarp
Monocarp所控制的角色处于
(
1
,
1
)
(1,1)
(1,1)格,终点在
(
2
,
n
)
(2,n)
(2,n)格。
角色每次移动时需要满足:
初
始
位
置
:
(
x
1
,
y
1
)
,
目
的
位
置
:
(
x
2
,
y
2
)
,
∣
x
1
−
x
2
∣
<
=
1
并
且
∣
y
1
−
y
2
∣
<
=
1
。
初始位置:(x_1,y_1),目的位置:(x_2,y_2),|x_1-x_2|<=1 并且 |y_1-y_2|<=1。
初始位置:(x1,y1),目的位置:(x2,y2),∣x1−x2∣<=1并且∣y1−y2∣<=1。
现在问你, M o n o c a r p Monocarp Monocarp是否可以通关?
思路
又是一个为数不多的在奇怪时间点开始的比赛。
看到这题的时候脑子犯抽,想的是直接用
B
F
S
BFS
BFS搜就完事了。
结果刚开始敲
B
F
S
BFS
BFS函数的时候突然想到:这好像只是一个简单的思维题吧。
为了防止掉大分,博主当时就跑路了。
结果跟我想的一样,压根就不用搜索。
M
o
n
o
c
a
r
p
Monocarp
Monocarp在向右边前进的过程中,假设他现在在
(
1
,
j
)
(1,j)
(1,j),根据条件限制我们可以推断出,只有一种情况可以阻碍他前进到下一列:(1,j+1)==1 && (2,j+1)==1
。
所以我们只需要找有没有一列的数字都是1的情况,有的话
M
o
n
o
c
a
r
p
Monocarp
Monocarp就没法通关了。
推出以上结论的关键是看懂人物的移动方式。
AC代码
#include<bits/stdc++.h>
using namespace std;
const long long mod=1e9+7;
string ss[3];
int main()
{
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
string flag="YES";
cin>>ss[0]>>ss[1];
for(int i=0;i<n;i++)
if(ss[0][i]==ss[1][i]&&ss[1][i]=='1'){
flag="NO";
break;
}
cout<<flag<<endl;
}
}
B. Groups(暴力+水题)
比赛链接:https://codeforces.com/contest/1598/problem/B
题目大意
现在你得到了一个二维数组
a
a
a,用于表示
n
n
n(
n
n
n一定是偶数)个同学一周的课程情况。
若
a
[
i
]
[
j
]
=
=
0
a[i][j]==0
a[i][j]==0,则说明学生
i
i
i在周
j
j
j那一天有课;若
a
[
i
]
[
j
]
=
=
1
a[i][j]==1
a[i][j]==1,则说明学生
i
i
i在周
j
j
j那一天没课。
现在老师想要给这
n
n
n个人分成两批进行补课,两批学生的人数相同,每个学生只补一次课。学生只有在没课的那天才能接受补课。
老师想知道他是否可以找到合适的两天给学生补课。
思路
一开始没太看懂,主要是有一点点的绕。
我们暴力枚举出补课的日期
i
、
j
i、j
i、j,然后将所有学生分为
4
4
4种:
1
1
1.可以在第
i
i
i天补课,也可以在第
j
j
j天补课;
2
2
2.可以在第
i
i
i天补课,不可以在第
j
j
j天补课;
3
3
3.不可以在第
i
i
i天补课,可以在第
j
j
j天上补课;
4
4
4.不可以在第
i
i
i天补课,不可以在第
j
j
j天补课;
那么补课日期 i 、 j i、j i、j可以被选用的条件就是:没有第 4 4 4种学生,第 2 2 2种学生与第 3 3 3种学生的数量都小于等于 n / 2 。 n/2。 n/2。
AC代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int arr[1050][10];
int main()
{
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
for(int i=1; i<=n; i++)
{
for(int j=1; j<=5; j++)
cin>>arr[i][j];
}
string flag="NO";
for(int i=1; i<=5; i++)
{
for(int j=i+1; j<=5; j++)
{
int a=0,b=0,c=0,d=0;
for(int k=1; k<=n; k++)
{
if(arr[k][i]==0&&arr[k][j]==0)
a++;
if(arr[k][i]==0&&arr[k][j]==1)
b++;
if(arr[k][i]==1&&arr[k][j]==0)
c++;
if(arr[k][i]==1&&arr[k][j]==1)
d++;
}
if(a==0&&b<=n/2&&c<=n/2)
{
flag="YES";
break;
}
}
if(flag=="YES") break;
}
cout<<flag<<endl;
}
}
C. Delete Two Elements(数学公式转换)
比赛链接:https://codeforces.com/contest/1598/problem/C
题目大意
我们把一个数组所有数的和 s u m sum sum除以数组长度 n n n的值 s u m / n sum/n sum/n记作 k k k。
现在我要在数组中随便删除两个数字
a
i
ai
ai与
a
j
aj
aj,数组的
k
k
k会变成
k
′
k'
k′。
请问我可以找到多少对不同的
(
i
,
j
)
(i,j)
(i,j),使得我删掉
a
i
ai
ai与
a
j
aj
aj之后,
k
′
k'
k′仍然等于
k
k
k。
思路
一开始我还以为是个数论,仔细看了看之后发现是老朋友——公式转换。
我们把题目中描述的公式写出:
s
u
m
/
n
=
=
[
s
u
m
−
(
a
i
+
a
j
)
]
/
(
n
−
2
)
sum/n==[sum-(a_i+a_j)]/(n-2)
sum/n==[sum−(ai+aj)]/(n−2)
除法这个东西只要不是整除,就一定会出现浮点数,而浮点数就很容易出现精度问题。
所以我们需要改一下式子,要乘不要除。
=
>
s
u
m
∗
(
n
−
2
)
=
=
[
s
u
m
−
(
a
i
+
a
j
)
]
∗
n
=>sum*(n-2)==[sum-(a_i+a_j)]*n
=>sum∗(n−2)==[sum−(ai+aj)]∗n
=
>
s
u
m
∗
2
=
=
(
a
i
+
a
j
)
∗
n
=>sum*2==(a_i+a_j)*n
=>sum∗2==(ai+aj)∗n
此时问题就简单了:在数组中找有多少对数字相加满足 s u m ∗ 2 = = ( a i + a j ) ∗ n sum*2==(a_i+a_j)*n sum∗2==(ai+aj)∗n即可。
AC代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
int t,n;
cin>>t;
while(t--)
{
ll sum=0,x;
int n;
cin>>n;
//if(n==200000) getdata();
map<ll,int> mp;
for(int i=0; i<n; i++)
{
cin>>x;
sum+=x;
mp[x]++;
}
map<ll,int>::iterator it;
ll ans=0;
for(it=mp.begin(); it!=mp.end(); it++)
{
//cout<<it->first<<endl;
int y=2*sum/n-(it->first);
if(mp[y])
{
if(((it->first)+y)*n==sum*2)
{
if(y==it->first) ans+=(1LL)*(it->second)*(it->second-1)/2;
else ans+=(1LL)*(it->second)*mp[y]; //1LL的原因是在第8个样例中,(it->second)*mp[y]爆出了int的范围,所以强转一下
it->second=0;
}
}
}
cout<<ans<<endl;
}
}
D. Training Session(逆向思维+map活用+排列组合)
比赛链接:https://codeforces.com/contest/1598/problem/D
题目大意
给出n对 ( a i , b i ) (ai,bi) (ai,bi),你现在需要在这 n n n对中挑出三个,这三个 ( a i , b i ) (ai,bi) (ai,bi)需要至少满足下述条件中的一个:
- 三个 a a a互不相同
- 三个 b b b互不相同
问可以找到多少个符合条件的三元组。
思路
正着做不是很好做,我们反着来,就是用所有的情况减去不符合的情况。
所有情况的数量:
C
n
3
C_{n}^{3}
Cn3。
不符合条件的数量求起来其实也很简单,既然要求上说
3
3
3个
(
a
i
,
b
i
)
(ai,bi)
(ai,bi)中
a
,
b
a,b
a,b都会不相同,那我们就至少保证选出的
3
3
3个
(
a
i
,
b
i
)
(ai,bi)
(ai,bi)中有两个
a
a
a是相同的,两个
b
b
b是相同的。
我们每一次都枚举
b
b
b的数值,那么当前
b
b
b不满足条件的总数就为:
(和
b
b
b相同个数的
−
1
-1
−1)*
∑
\sum
∑(与
b
b
b对着的所有
a
a
a的个数
−
1
-1
−1)。
AC代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
int t;
cin>>t;
while(t--)
{
ll n;ll a,b;
cin>>n;
map<ll,ll> mpa,mpb;
map<ll,vector<ll> > mp;
///n*(n-1)*(n-2)/6
ll sum=n*(n-1)*(n-2)/6;
for(int i=1;i<=n;i++){
cin>>a>>b;
mpa[a]++;
mpb[b]++;
mp[b].push_back(a);
}
for(map<ll,ll>::iterator it=mpb.begin();it!=mpb.end();it++){
ll tmp=0;
for(int i=0;i<mp[it->first].size();i++){
tmp+=(it->second-1)*(mpa[mp[it->first][i]]-1);
}
sum-=tmp;
}
cout<<sum<<endl;
}
}
感谢阅读,希望能对你产生一点用处。