2020 第七届Code+程序设计全国挑战赛 normal 部分题解

A:最小路径串

2020 第七届Code+程序设计全国挑战赛 normal 部分题解_第1张图片
2020 第七届Code+程序设计全国挑战赛 normal 部分题解_第2张图片
2020 第七届Code+程序设计全国挑战赛 normal 部分题解_第3张图片

做法:
1.直接建图跑最短路,按照字典序规则。但建图需要花很多的空间,只能过前两个子任务。第三个MLE

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
const int maxn=1e6+10;
const int mode=998244353;
const int inf=0x3f3f3f3f;
typedef long long ll;
int n,m;
string s;
map <int,string> mp;

struct edge{
    int u,v,next;
    string w;
}e[maxn<<1];
int head[maxn],cnt=0;

struct DS{
    string s;
    int u;
    bool operator < (const DS&rhs) const{
        int l1=s.length();
        int l2=rhs.s.length();

        int l=min(l1,l2);
        for (int i=0;i<l;i++){
            if(s[i] < rhs.s[i]) return false;
            else if(s[i] > rhs.s[i]) return true;
            else{
                continue;
            }
        }
        if (l == l1) return false;
        else return true;
    }
    DS(string str,int uu):s(str),u(uu){}
};

void add(int u,int v){
    e[++cnt].v=v;
    e[cnt].next=head[u];
    head[u]=cnt;
}

int change_to_int(string s){
    int sum = 0;
    int f = 100000; 
    for (int i=0;i<s.length();i++){
        sum += (s[i]-'0') * f;
        f/=10;
    }
    return sum;
}

void init(){
    int l = s.length();
    for (int i=0; i<l;i+=12){
        string sub1 = s.substr(i,6);
        string sub2 = s.substr(i+6,6);
        int u = change_to_int(sub1);
        int v = change_to_int(sub2);
        add(u,v);
        add(v,u);
        if(mp[u] == "") mp[u] = sub1;
        if(mp[v] == "") mp[v] = sub2;
    }
}
string str_d[maxn];
ll d[maxn];
bool vis[maxn];

void solve(){
    for (int i=0;i<n;i++){
        str_d[i] = "9";
        d[i] = inf;
        vis[i] = 0;
    }
    str_d[0] = "000000";
    d[0] = 0;
    priority_queue<DS> q;
    q.push(DS(mp[0],0));
    while(!q.empty()){
        DS ds= q.top();
        int u = ds.u;
        string sub = ds.s;
        q.pop();
        if (vis[u]) continue;
        vis[u] = true;
        
        for (int i=head[u];i;i=e[i].next){
            int v=e[i].v;
            // if(vis[v]) continue;
            string temp = sub + mp[v];
            if(str_d[v].compare(temp) > 0) {
                str_d[v] = temp;
                q.push(DS(str_d[v],v));
                d[v] = (1000000 *d[u] + v) % mode;
            }
        }
    }
}

void print(){
    for (int i=1;i<n;i++){
        if(d[i] == inf) puts("-1");
        else{
            printf("%lld\n",d[i]);
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);
    getchar();
    getline(cin,s);
    init();
    solve();
    print();
    return 0;
}
/*
5 5
000000000003000001000003000001000002000002000000000002000003
*/

2.正解:用优先队列存图,每次取队列中序号最小的那个点,则可以保证字符串连接时候的字典序最小。然后从0点跑dfs,第一次到任何一个点时候的路径即为点0到这个点的路径最小值。(很神奇的建图方法)

#include 
using namespace std;
const int maxn=1e6+10;
const int mode=998244353;
const int inf=0x3f3f3f3f;
typedef long long ll;

string s;
int n,m;
ll d[maxn];
bool vis[maxn];

priority_queue<int,vector<int>,greater<int> > Map[maxn];
void dfs(int x,ll dis){
    while(!Map[x].empty()){
        int v = Map[x].top();
        Map[x].pop();
        if(vis[v]) continue;
        ll temp = (dis*1000000 + v) % mode;
        vis[v] = true;
        d[v] =temp;
        dfs(v,temp);
    }
}

int change_to_int(string s){
    int sum = 0;
    int f = 100000; 
    for (int i=0;i<s.length();i++){
        sum += (s[i]-'0') * f;
        f/=10;
    }
    return sum;
}

void init(){
    int l = s.length();
    for (int i=0; i<l;i+=12){
        string sub1 = s.substr(i,6);
        string sub2 = s.substr(i+6,6);
        int u = change_to_int(sub1);
        int v = change_to_int(sub2);
        Map[u].push(v);
        Map[v].push(u);
    }
}

int main(){
    cin>>n>>m;
    getchar();
    getline(cin,s);
    for (int i=1;i<n;i++) {
        d[i] = inf;
        vis[i] = 0;
    }
    vis[0] = true;
    init();
    dfs(0,0);
    for (int i=1;i<n;i++){
        if(d[i] == inf) puts("-1");
        else printf("%lld\n",d[i]);
    }
    return 0;
}

B:

#include 

using namespace std;
typedef long long ll;
const int Maxn = 1e5+10;
const int Inf = 0x7f7f7f7f;
const int Mod = 1e9+7;

int a[Maxn],v[Maxn];
int l_0[Maxn],r_1[Maxn];
double ans[Maxn];
int _1[Maxn],tol1,_0[Maxn],tol0;

int main(){
    int n,l;
    scanf("%d %d",&n,&l);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)
        scanf("%d",&v[i]);

    for(int i=1;i<=n;i++)
        if( v[i] == 1 )
            r_1[i] = r_1[i-1] + 1,_1[++tol1] = a[i];
        else r_1[i] = r_1[i-1];
    for(int i=n;i>=1;i--)
        if( v[i] == 0 )
            l_0[i] = l_0[i+1] + 1,_0[++tol0] = a[i];
        else l_0[i] = l_0[i+1];
    
    for(int i=1;i<=n;i++)
    {
        double time,dis;
        int dir;
        if( v[i] == 1 )
        {
            if( l_0[i] >= r_1[i] )
            {
                int tmp = l_0[i] - r_1[i];
                dir = 0;
                dis = 1.0*(_1[1] + _0[tmp + 1])/2;
                time= -1.0*(_1[1] - _0[tmp + 1])/2;
            }
            else 
            {
                int tmp = r_1[i] - l_0[i];
                dir = 1;
                dis = 1.0*(_1[tmp] + _0[1])/2;
                time= -1.0*(_1[tmp] - _0[1])/2;
            }
        }
        else 
        {
            if( r_1[i] >= l_0[i] )
            {
                int tmp = r_1[i] - l_0[i];
                dir = 1;
                dis = 1.0*(_1[tmp+1] + _0[1])/2;
                time= -1.0*(_1[tmp+1] - _0[1])/2;
            }
            else 
            {
                int tmp = l_0[i] - r_1[i];
                dir = 0;
                dis = 1.0*(_1[1] + _0[tmp])/2;
                time= -1.0*(_1[1] - _0[tmp])/2;
            }
        }
        if( dir == 0 )  ans[i] = time + dis;
        else ans[i] = time + l-dis;
    }
    for(int i=1;i<=n;i++)
        printf("%lld ",(ll)(ans[i]+0.5));
    return 0;
}

你可能感兴趣的:(2020 第七届Code+程序设计全国挑战赛 normal 部分题解)