• Codeforces Round #403 (Div. 2) B 二分或三分 D 2-sat E 思维,dfs


    Codeforces Round #403 (Div. 2, based on Technocup 2017 Finals)

    B. The Meeting Place Cannot Be Changed

    题意:n个人,各自在点x[i],每个人最大速度v[i],可以往左右两个方向走。要使这n个人在同一个点相聚,求最小时间。

    tags:可以直接三分位置,有个坑,eps取1e-7竟然会超时,取1e-6就过了;另外三分也不知道怎么搞出单调性的,貌似大家都是“显然”,23333。。可以二分时间求交集,但在求交集时有点技巧,不断比较出左界最大值a和右界最小值b,看最后是否有a<=b

    // 二分
    #include<bits/stdc++.h>
    using namespace std;
    #pragma comment(linker, "/STACK:102400000,102400000")
    #define rep(i,a,b) for (int i=a;i<=b;i++)
    #define per(i,b,a) for (int i=b;i>=a;i--)
    #define mes(a,b)  memset(a,b,sizeof(a))
    #define INF 0x3f3f3f3f
    typedef long long ll;
    const int N = 60005;
    
    int n, x[N], v[N];
    bool check(double t)
    {
        double minn=2000000005, maxn=0;
        rep(i,1,n) {
            minn=min(minn, x[i]+v[i]*t);
            maxn=max(maxn, x[i]-v[i]*t);
        }
        return maxn<=minn;
    }
    int main()
    {
        scanf("%d", &n);
        rep(i,1,n) scanf("%d", &x[i]);
        rep(i,1,n) scanf("%d", &v[i]);
        double l=0, r=1000000005, ans;
        while(fabs(r-l)>1e-7) {
            double mid=(l+(r-l)/2);
            if(check(mid)) r=mid, ans=mid;
            else l=mid;
        }
        printf("%.12f
    ", ans);
    
        return 0;
    }
    二分
    // 三分
    #include<bits/stdc++.h>
    using namespace std;
    #pragma comment(linker, "/STACK:102400000,102400000")
    #define rep(i,a,b) for (int i=a;i<=b;i++)
    #define per(i,b,a) for (int i=b;i>=a;i--)
    #define mes(a,b)  memset(a,b,sizeof(a))
    #define INF 0x3f3f3f3f
    typedef long long ll;
    const int N = 60005;
    
    int n;
    double x[N], v[N];
    double cal(double xi)
    {
        double res=0;
        rep(i,1,n) res=max(res, fabs(xi-x[i])/v[i]);
        return res;
    }
    int main()
    {
        scanf("%d", &n);
        rep(i,1,n) scanf("%lf", &x[i]);
        rep(i,1,n) scanf("%lf", &v[i]);
        double l=0, r=1000000005;
        while(fabs(r-l)>1e-6) {
            double m1=l+(r-l)/3, m2=r-(r-l)/3;
            double t1=cal(m1), t2=cal(m2);
            if(t1<t2) r=m2;
            else l=m1;
        }
        printf("%.12f
    ", cal(l));
    
        return 0;
    }
    三分

    D. Innokenty and a Football League

    题意:每个团队有两个单词s1,s2,有两种取名字的方法:1、a=s1[0]+s1[1]+s1[2];2、a'=s1[0]+s1[1]+s2[0]。限制:每个团队名字不能相同,而且,如果一个团队以第二种方法取名a',其它团队就不能以第一种方法取名a。求是否可能给每个团队都取名。

    tags:第一次写2-sat,强行码了一发。。这题还有用贪心的,但感觉好玄   

    每个团队都只能在2种可能里选一种,而各个团队的可能又会互相影响,即裸的2判定性问题。

    #include<bits/stdc++.h>
    using namespace std;
    #pragma comment(linker, "/STACK:102400000,102400000")
    #define rep(i,a,b) for (int i=a;i<=b;i++)
    #define per(i,b,a) for (int i=b;i>=a;i--)
    #define mes(a,b)  memset(a,b,sizeof(a))
    #define INF 0x3f3f3f3f
    typedef long long ll;
    const int N = 200005;
    
    int n, m, k, tot, head[N];
    string s[3];
    map<string, int >mp;
    map<int , string>pm;
    struct Club{int fir, sec;}a[N];
    struct Edge{int to, next;}e[N];
    void Addedge(int u, int v){e[++tot].to=v, e[tot].next=head[u], head[u]=tot;}
    
    bool vis[N];
    int Stack[N], top;
    bool dfs(int u)
    {
        if(vis[u^1]) return false;
        if(vis[u]) return true;
        vis[u]=true;
        Stack[top++]=u;
        for(int i=head[u]; i; i=e[i].next)
            if(dfs(e[i].to)==0) return false;
        return true;
    }
    bool Twosat(int n)     //n
    {
        memset(vis,false,sizeof(vis));
        for(int i=0; i<n; i+=2) {       //i+=2
            if(vis[i] || vis[i^1]) continue;
            top=0;
            if(dfs(i)==0) {
                while(top) vis[Stack[--top]]=false; //记录路径
                if(dfs(i^1)==0) return false;   //如果矛盾返回flase
            }
        }
        return true;
    }
    
    int main()
    {
        scanf("%d", &n);
        rep(i,1,n) {
            cin>>s[1]>>s[2];
            string s1=s[1].substr(0,3);
            string s2=s[1].substr(0,2)+s[2][0];
            if(mp[s1]==0) mp[s1]=++k, pm[k]=s1;
            if(mp[s2]==0) mp[s2]=++k, pm[k]=s2;
            a[i].fir=mp[s1], a[i].sec=mp[s2];
        }
        rep(i,1,n) rep(j,1,n) {     //加边,不太理解
            if(i==j) continue;
            if(a[i].fir==a[j].fir) Addedge(2*i-2, 2*j-1), Addedge(2*i-1, 2*j-1);
            if(a[i].fir==a[j].sec) Addedge(2*i-2, 2*j-2);
            if(a[i].sec==a[j].fir) Addedge(2*i-1, 2*j-1);
            if(a[i].sec==a[j].sec) Addedge(2*i-1, 2*j-2);
        }
        if(Twosat(2*n)) {           //2*n
            puts("YES");
            rep(i,0,2*n-1) if(vis[i]) {
                if((i+1)&1) cout<<pm[a[(i+2)/2].fir]<<endl;
                else cout<<pm[a[(i+1)/2].sec]<<endl;
            }
        } else {
            puts("NO");
        }
    
        return 0;
    }
    View Code

    E. Underground Lab

    题意:n个点m条无向边k个人,每个人每秒可以走过一条边。每个人最多可以经过 2n/k 个点(可重复),要使得最终n个点都至少被一个人遍历过,求每个人的路径走法。

    tags:考思维,想不到啊mdzz

    因为每个人最多可经过2n/k个点,k个人即最多可经过2n个点。这样的话,我们可以按dfs序搜一遍,把所有结点(包括dfs中重复的)都记录下来,再分配给这k个人即可。

    #include<bits/stdc++.h>
    using namespace std;
    #pragma comment(linker, "/STACK:102400000,102400000")
    #define rep(i,a,b) for (int i=a;i<=b;i++)
    #define per(i,b,a) for (int i=b;i>=a;i--)
    #define mes(a,b)  memset(a,b,sizeof(a))
    #define INF 0x3f3f3f3f
    typedef long long ll;
    const int N = 200005;
    
    int n, m, k, path[N<<1], cnt;  //路径要开双倍
    bool vis[N];
    vector<int >G[N];
    void dfs(int u)
    {
        vis[u]=1;
        path[++cnt]=u;
        for(auto v : G[u]) {
            if(vis[v]) continue;
            dfs(v);
            path[++cnt]=u;
        }
    }
    int main()
    {
        scanf("%d %d %d", &n, &m, &k);
        int u, v;
        rep(i,1,m) {
            scanf("%d %d", &u, &v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        dfs(1);
        int num=(2*n+k-1)/k, len;
        rep(i,1,k) {
            len=min(num, cnt);
            if(len==0) { printf("1 1
    "); continue; }
            printf("%d ", len);
            for(int i=0; i<len && cnt; i++, cnt--)
                printf("%d ", path[cnt]);
            puts("");
        }
    
        return 0;
    }
    View Code
  • 相关阅读:
    leetcode1161
    leetcode1160
    校招真题练习034 倒水(贝壳)
    校招真题练习033 音乐列表(贝壳)
    校招真题练习032 连续相同字符串(头条)
    校招真题练习031 三支球队比分(头条)
    leetcode1144
    ArrayQueue(队列)
    LinkQueue(链队)
    快速幂
  • 原文地址:https://www.cnblogs.com/sbfhy/p/6511426.html
Copyright © 2020-2023  润新知