[Gym 101755]UESTC 2018 Summer Training #12 Div.2初步题解

这是基于在目前能力内完成的题解。
这场比赛我做出了 6 6 6题,实际上可以做出 8 8 8题。
还有 1 1 1题是真的缺少了这类思想。
地址:实质上是一场 g y m gym gym
截止到现在:还剩下 D 、 G 、 I 、 F \color{red}D、G、I、F DGIF题未补

A A A: 已知 a 、 b a、b ab 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/k1。即是一个可行解。

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| aa2+b2 x1x2是底长,简单画个小相似三角形就可以演算。
对于直线 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(y1y2)+b(x1x2)=0
由于这里直线不一定要最简形式,直接 a = x 1 − x 2 , b = y 2 − y 1. a=x1-x2,b=y2-y1. a=x1x2,b=y2y1.
待会去即可计算。

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 nm总共是 200000 200000 200000级别的,所以不能直接开数组, m a p map map会超时。
但是我们实际上可以转换成一维数组: x = ( i − 1 ) ∗ m + j x=(i-1)*m+j x=(i1)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
#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
#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
#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");
}

你可能感兴趣的:(队内集训,队内补题)