这是基于在目前能力内完成的题解。
这场比赛我做出了
6
6
6题,实际上可以做出
8
8
8题。
还有
1
1
1题是真的缺少了这类思想。
地址:实质上是一场
g
y
m
gym
gym
截止到现在:还剩下
D
、
G
、
I
、
F
\color{red}D、G、I、F
D、G、I、F题未补
A
A
A: 已知
a
、
b
a、b
a、b的
s
u
m
sum
sum和
g
c
d
gcd
gcd,求出一组可能解
a
+
b
=
x
k
+
y
k
=
s
u
m
a+b=xk+yk=sum
a+b=xk+yk=sum
x
+
y
=
s
u
m
/
k
x+y=sum/k
x+y=sum/k
令
x
=
1
x=1
x=1,
y
=
s
u
m
/
k
−
1
y=sum/k-1
y=sum/k−1。即是一个可行解。
B
B
B: 求凸边形的由顶点组成的最小三角形面积的
2
2
2倍
选择一条边作为底,显然相邻顶点边最短。
找一个顶点形成高,同样也是相邻最短。
所以枚举相邻的三个点即可。
∣
a
x
+
b
y
+
c
∣
a
2
+
b
2
=
d
\frac{|ax+by+c|}{\sqrt{a^2+b^2}}=d
a2+b2∣ax+by+c∣=d点到直线距离
a
2
+
b
2
∣
a
∣
∗
∣
x
1
−
x
2
∣
\frac{\sqrt{a^2+b^2}}{|a|}*|x1-x2|
∣a∣a2+b2∗∣x1−x2∣是底长,简单画个小相似三角形就可以演算。
对于直线
a
x
+
b
y
+
c
=
0
ax+by+c=0
ax+by+c=0,转换成
y
=
−
b
a
x
+
c
a
y=-\frac{b}{a}x+\frac{c}{a}
y=−abx+ac
代入两个点:
a
(
y
1
−
y
2
)
+
b
(
x
1
−
x
2
)
=
0
a(y1-y2)+b(x1-x2)=0
a(y1−y2)+b(x1−x2)=0
由于这里直线不一定要最简形式,直接
a
=
x
1
−
x
2
,
b
=
y
2
−
y
1.
a=x1-x2,b=y2-y1.
a=x1−x2,b=y2−y1.
待会去即可计算。
C
C
C: 求选择最多的点,使得所有的区间都存在一个点在这些点之中。
优先把最长的放在前面,使得贪心地一次选取尽可能多的。
是没有后效性的,因为你这次选了之后,下次依然可以选到这个(多多益善:其实就是无所谓了)
所以先按左端点最近排序,再按右端点最远排序。
这样我们往下选知道交集区间等于空集为止,记录答案。
然后继续重新从这个点往下选。
这样每次选择的都是足够多的区间(因为按照最大的开始)。
E
E
E: 求
b
b
b是否存在子串反转之后得到
a
a
a
枚举不同的最左端点和最右端点。
最后对于这两点之间分别进行正向和反向遍历,判断是否相等。
没有断层不会有影响,有断层的话肯定不会符合条件。
H
H
H:二维空间,从起点走到终点,同时有些点存在怪兽,和怪兽的距离不能少于等于
d
d
d。求最短距离。
考场上差点就可以做出来了。
典型的四个方向,应该用
b
f
s
bfs
bfs来做。
但我们需要注意的是:
n
∗
m
n*m
n∗m总共是
200000
200000
200000级别的,所以不能直接开数组,
m
a
p
map
map会超时。
但是我们实际上可以转换成一维数组:
x
=
(
i
−
1
)
∗
m
+
j
x=(i-1)*m+j
x=(i−1)∗m+j。这样就可以满足条件了。
然后对于每个怪兽都跑一遍
b
f
s
bfs
bfs,事实上可以直接让所有怪兽入队。
同时距离一个
d
i
s
dis
dis数组记录当前走到的最小距离,每次走到
d
d
d之后不再走了。
有个特殊情况:遇到已经被赋值过的点不能够直接跳过,因为可能对于上个怪兽是走到极限才走到这里,对于现在的才刚刚到这。所以入队的时候判断是否比之前
d
i
s
dis
dis小即可。
最后正常的跑一遍 b f s bfs bfs即可出答案。(上面的复杂度比较玄学…但是是卡过去的所以我觉得加 m a p map map过不了)
#include<bits/stdc++.h>
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define ll long long
#define ull unsigned long long
using namespace std;
const int maxn = 200050;
const int maxm = 2000050;
int X[]={1,-1,0,0};
int Y[]={0,0,1,-1};
int n,m,d,dis[maxn];
bool vis[maxn];
pair<int,int>s,t;
vector<pair<int,int> >monster;
struct node{
int x,y,dist;
};
bool check(int x,int y){
if(x>=1&&x<=n)
if(y>=1&&y<=m)
return true;
return false;
}
void bfs_init(){
queue<node>q;
memset(dis,0x3f,sizeof(dis));
for(int i=0;i<monster.size();i++){
q.push(node{monster[i].first,monster[i].second,0});
}
while(!q.empty()){
int nowi=q.front().x,nowj=q.front().y,step=q.front().dist;
q.pop();
vis[(nowi-1)*m+nowj]=true;
if(step==d)continue;
for(int k=0;k<4;k++){
int xx=nowi+X[k],yy=nowj+Y[k];
if(check(xx,yy)){
if(step+1<dis[(xx-1)*m+yy]){
dis[(xx-1)*m+yy]=step+1;
q.push(node{xx,yy,step+1});
}
}
}
}
}
int bfs_slove(int i,int j){
queue<node>q;
q.push(node{i,j,0});
while(!q.empty()){
int nowi=q.front().x,nowj=q.front().y,step=q.front().dist;
q.pop();
if(vis[(nowi-1)*m+nowj])continue;
if(nowi==t.first&&nowj==t.second){
return step;
}
vis[(nowi-1)*m+nowj]=true;
for(int k=0;k<4;k++){
int xx=nowi+X[k],yy=nowj+Y[k];
if(check(xx,yy)&&!vis[(xx-1)*m+yy]){
q.push(node{xx,yy,step+1});
}
}
}
return -1;
}
int main(){
cin>>n>>m>>d;
for(int i=1;i<=n;i++){
string str;cin>>str;
for(int j=1;j<=str.size();j++){
if(str[j-1]=='S')s.first=i,s.second=j;
if(str[j-1]=='F')t.first=i,t.second=j;
if(str[j-1]=='M')monster.push_back(make_pair(i,j));
}
}
bfs_init();
/*for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
printf("%d",vis[(i-1)*m+j]);
}
puts("");
}*/
cout<<bfs_slove(s.first,s.second)<<endl;
}
J J J:太简单了不说啦。
K
K
K: 从
n
n
n个人中要求得到
m
m
m个人。
第
i
第i
第i个人被得到仅当前面有
a
i
a_i
ai个人已经得到了或者被说服。要求求出最少说服人数。
如果我们对人数进行限制,那么肯定优先用造成的效果最好。所以我们一旦不能得到就直接说服,直到没得用为止,最后判断是否能到达
m
m
m.
显然二分。
L
L
L: 有一个串
a
a
a,和一个空串
b
b
b,对空串
b
b
b进行
p
u
s
h
push
push和
p
o
p
pop
pop操作(在尾部)。每次操作判断
b
b
b是否是
a
a
a的子序列(不需要连续)。
这就是没有这类思想的所以没做出来的一题。
思想就是最近一场
c
f
cf
cf类似的倍增跳跳跳,这里只是沿用思想,用
n
e
x
t
[
i
]
[
j
]
next[i][j]
next[i][j]存放第i个位置后第j个字符出现的第一个位置。
我们在
p
u
s
h
push
push的时候,判断并更新当前位置。
p
o
p
pop
pop也是如此,不过因为弹出的时候没有记录,最好用
p
a
i
r
pair
pair记录一下放进
s
t
a
c
k
stack
stack。
不过我用了另一个办法做,就是存放字符所有位置,然后二分。
#include<bits/stdc++.h>
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define ll long long
#define ull unsigned long long
using namespace std;
string s;
vector<int>G[30];
stack<pair<int,int> >st;
int main(){
cin>>s;
int m,now=-1;
for(int i=0;i<s.size();i++){
G[s[i]-'a'+1].push_back(i);
}
cin>>m;
while(m--){
cin>>s;
if(s[1]=='u'){
cin>>s;
int x=s[0]-'a'+1;
int index=upper_bound(G[x].begin(),G[x].end(),now)-G[x].begin();
if(index>=G[x].size()){
puts("NO");
now=0x3f3f3f3f;
}
else{
puts("YES");
now=G[x][index];
}
st.push(make_pair(x,index));
}
else{
st.pop();
if(!st.empty()){
if(st.top().second>=G[st.top().first].size()){
puts("NO");
now=0x3f3f3f3f;
}
else{
puts("YES");
now=G[st.top().first][st.top().second];
}
}
else{
now=-1;
puts("YES");
}
}
}
}
M
M
M:有三个字符串,每个字符串最多错一个字符,求的原始字符串。不确定输出
a
m
b
i
g
o
u
s
ambigous
ambigous。不可能输出
i
m
p
o
s
s
i
b
l
e
impossible
impossible。
很简单的一道模拟题,只是情况比较多而已。
所以没做真的是血亏。虽然麻烦但是一个小时可以做完的,开错题了真的。
字符串不同只有两种情况:两个相同,一个不同和三个不同。
1、后者只可能有一个是对的(都不对就无法确定了。),但这样也是无法确定的,必须有前者,并且前者是不同的那一个必须是错的,否则是不满足的。(因为至多错一个了,后者以及错了两个)
2、对于前者,只有1个是不确定的。两个的话,如果不同出现在两个字符串那么可以确定。出现在相同则是不确定的。
3、对于前者,三个的时候,只有三个都不同才是可以确定的,否则不可以确定。
这就是所有情况了,没细说。摆代码把。
#include<bits/stdc++.h>
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define ll long long
#define ull unsigned long long
using namespace std;
string a,b,c;
int usea=0,useb=0,usec=0;
int one=0,all=0;
void slove(int mark){
string str="";
usea=useb=usec=-1;
for(int i=0;i<a.size();i++){
if(a[i]!=b[i]&&b[i]!=c[i]&&a[i]!=c[i])all=i,str+=a[i];
else if(a[i]==b[i]&&c[i]!=a[i])usec=i,str+=a[i];
else if(a[i]==c[i]&&b[i]!=a[i])useb=i,str+=a[i];
else if(b[i]==c[i]&&a[i]!=b[i])usea=i,str+=b[i];
else str+=a[i];
}
if(mark==1||mark==2)cout<<str<<endl;
if(mark==3){
if(usea>=0)str[all]=a[all];
if(useb>=0)str[all]=b[all];
if(usec>=0)str[all]=c[all];
cout<<str<<endl;
}
}
int main(){
cin>>a>>b>>c;
for(int i=0;i<a.size();i++){
if(a[i]!=b[i]&&b[i]!=c[i]&&a[i]!=c[i])all++;
else if(a[i]==b[i]&&c[i]!=a[i])one++,usec++;
else if(a[i]==c[i]&&b[i]!=a[i])one++,useb++;
else if(b[i]==c[i]&&a[i]!=b[i])one++,usea++;
}
if(one==0&&all==0){
puts("Ambiguous");
}
else if(one==3&&all==0){
if(usea==1&&useb==1&&usec==1)slove(1);
else puts("Impossible");
}
else if(one==2&&all==0){
if(usea==useb&&usea>0)slove(2);
else if(usea==usec&&usea>0)slove(2);
else if(useb==usec&&usec>0)slove(2);
else if(usea==2)puts("Ambiguous");
else if(useb==2)puts("Ambiguous");
else if(usec==2)puts("Ambiguous");
else puts("Impossible");
}
else if(one==1&&all==0){
puts("Ambiguous");
}
else if(one==0&&all==1){
puts("Ambiguous");
}
else if(one==1&&all==1){
slove(3);
}
else puts("Impossible");
}