• 《HDU多校第四场》


    Equal Sentences

    思路:因为下标的限制,交换后位置不能和原来超过1。

    那么,和后面交换,可以看成后面的和前面的交换。

    那么对于每一个位置,只需要看和前面交换即可。

    对于没有冲的ABCD类的位置交换组合。

    经过递推之后,可以发现就是个斐波那契数列。

    当引入了重复后,从只和前面的交换来看。

    用dp[i]来表示到i的方案数

    首先加入i点,方案为dp[i-1].

    如果和前面不重复,那么交换后会形成新的方案,即dp[i-2]

    所以转移方程即为dp[i] = dp[i-1] + (s[i] == s[i-1] ? 0 : dp[i-2])

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef long double ld;
    typedef pair<int,int> pii;
    const int N = 2e5+5;
    const int M = 2e5+5;
    const LL Mod = 1e9+7;
    #define rg register
    #define pi acos(-1)
    #define INF 1e18
    #define INM INT_MIN
    #define dbg(ax) cout << "now this num is " << ax << endl;
    inline int read()
    {
        int x = 0,f = 1;char c = getchar();
        while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
        return x*f;
    }
    LL dp[N];
    string t[N];
    int main()
    {
        int ca;ca = read();
        while(ca--)
        {
            int n;n = read();
            string s;getline(cin,s);
            memset(dp,0,sizeof(dp));
            int len = s.size(),k = 0;
            string tt = "";
            for(int i = 0;i < len;++i)
            {
                if(s[i] == ' ')
                {
                    t[++k] = tt;
                    tt = "";
                }
                else tt += s[i];
            }
            t[++k] = tt;
            dp[1] = 1,dp[0] = 1;
            for(int i = 2;i <= n;++i)
            {
                dp[i] = dp[i-1];
                if(t[i] != t[i-1]) dp[i] = (dp[i]+dp[i-2])%Mod;
            }
            printf("%lld\n",dp[n]);
        }
        //system("pause");
        return 0;
    }
    View Code

    Deliver the Cake

    思路:一开始只是在最短路上进行模改,然后直接跑。

    一直TLE。因为可能会多次去改变一个点的最优状态,导致了时间复杂度飙升。

    正解:对于L,R这些点,很显然在这个城市上,就应该是哪只手,所以需要考虑的只是在M城市上应该是哪只手。

    又因为在M城市上显然只有两种可能,那么进行拆点,对于M城市建立两个点,一个是左手点,一个是右手点。

    然后对相邻的点连边,如果不同就加上代价x。

    需要注意的是,s和t也可能拆过,所以最优解应该是在min(dis{s1,s2} - {t1,t2})

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef long double ld;
    typedef pair<LL,int> pii;
    const int N = 1e5+5;
    const int M = 2e5+5;
    const LL Mod = 1e9+7;
    #define rg register
    #define pi acos(-1)
    #define INF 1e18
    #define INM INT_MIN
    #define dbg(ax) cout << "now this num is " << ax << endl;
    inline LL read()
    {
        LL x = 0,f = 1;char c = getchar();
        while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
        return x*f;
    }
    int n,m,s,t,col[N<<1],head[N<<1],cnt = 0;
    LL x,dis[N<<1];
    char ss[N];
    struct Node{int to,next;LL dis;}e[M*8];
    inline void add(int u,int v,LL w)
    {
        e[++cnt].to = v,e[cnt].dis = w,e[cnt].next = head[u],head[u] = cnt;
        e[++cnt].to = u,e[cnt].dis = w,e[cnt].next = head[v],head[v] = cnt;
    }
    void dij(int st)
    {
        for(int i = 1;i <= n*2;++i) dis[i] = INF;
        dis[st] = 0;
        priority_queue<pii,vector<pii>,greater<pii> > Q;
        Q.push(pii{0,st});
        while(!Q.empty())
        {
            int u = Q.top().second;
            LL d = Q.top().first;
            Q.pop();
            if(d > dis[u]) continue;
            for(int i = head[u];i;i = e[i].next)
            {
                int v = e[i].to;LL dd = e[i].dis;
                if(dis[v] > dis[u]+dd)
                {
                    dis[v] = dis[u]+dd;
                    Q.push(pii{dis[v],v});
                }
            }
        }
    }
    int main()
    {
        int ca;ca = read();
        while(ca--)
        {
            n = read(),m = read(),s = read(),t = read(),x = read();
            cnt = 0;
            memset(head,0,sizeof(head));
            scanf("%s",ss);
            int len = strlen(ss);
            for(rg int i = 0;i < len;++i) 
            {
                if(ss[i] == 'L') col[i+1] = -1;
                else if(ss[i] == 'R') col[i+1] = 1;
                else col[i+1] = 0;
            }
            while(m--)
            {
                int u,v;
                LL w;//小 - 左,大 - 右
                u = read(),v = read(),w = read();
                if(col[u] != 0 && col[v] == 0) swap(u,v);
                if(col[u] == 0) 
                {
                    if(col[v] == 0)
                    {
                        add(u,v,w);//左 - 左
                        add(u+n,v+n,w);//右 - 右
                        add(u,v+n,w+x);//左 - 右
                        add(u+n,v,w+x);//右 - 左
                    }
                    else if(col[v] == -1)
                    {
                        add(u,v,w);//左 - 左
                        add(u+n,v,w+x);//右 - 左
                    }
                    else
                    {
                        add(u,v,w+x);//左 - 右
                        add(u+n,v,w);//右 - 右
                    }
                }
                else 
                {
                    int ma = (col[u] == col[v] ? 0 : x);
                    add(u,v,w+ma);
                }
            }
            LL ans = INF;
            dij(s);
            ans = min(ans,min(dis[t],dis[t+n]));
            if(col[s] == 0) 
            {
                dij(s+n);
                ans = min(ans,min(dis[t],dis[t+n]));
            }
            printf("%lld\n",ans);
        }
        system("pause");
        return 0;
    }
    /*
    1 
    3 3 1 3 20
    MRM
    1 2 10
    2 3 10
    1 3 100
    ans - 20
    */
    View Code

    Go Running

    思路:从坐标轴出发。x为纵坐标,t为横坐标

    因为每个人每秒钟只走1的单位距离。

    那么可以发现对于每个人的运动坐标,都是k = 1或-1的直线(= 1向东走,-1向西走)

    这坐标轴上可见,每个人都有两条直线延伸到的可能。每个人都会被一条直线覆盖到。

    当一条直线覆盖到多个人时,这条直线上的人都可能是一个人跑的。

    那么显然要最小化选到的直线,让这些直线覆盖到所有点。

    如果让点和直线连边,会发现难以实现。因为一个人会连正值k线和负值k线,变得很困难。

    那么如果让正值k线和负值k线连边,可以发现就是一个二分图的模型。

    我们要选择较少的正k值k线,覆盖了所有的负值k线。那么就是个最小点覆盖的问题。

    匈牙利会超时,直接上HK

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef long double ld;
    typedef pair<LL,int> pii;
    const int N = 1e5+5;
    const int M = 2e5+5;
    const LL Mod = 1e9+7;
    #define rg register
    #define pi acos(-1)
    #define INF 1e18
    #define INM INT_MIN
    #define dbg(ax) cout << "now this num is " << ax << endl;
    inline LL read()
    {
        LL x = 0,f = 1;char c = getchar();
        while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
        return x*f;
    }
    int match[N],tag[N],vis[N],n,cnt1,cnt2;
    int dx[N],dy[N];
    vector<int> G[N];
    bool bfs()
    {
        memset(dx,0,sizeof(dx));
        memset(dy,0,sizeof(dy));
        bool flag = false;
        queue<int> Q;
        for(int i = 1;i <= cnt1;++i) if(tag[i] == -1) Q.push(i);
        while(!Q.empty())
        {
            int u = Q.front();
            Q.pop();
            for(auto v : G[u])
            {
                if(dy[v] != 0) continue;
                dy[v] = dx[u]+1;
                if(match[v] == -1) flag = true;
                else
                {
                    dx[match[v]] = dy[v]+1;
                    Q.push(match[v]);
                }
            }
        }
        return flag;
    }
    bool Find(int x)
    {
        for(auto v : G[x])
        {
            if(vis[v] || dy[v] != dx[x]+1) continue;
            vis[v] = 1;
            if(match[v] == -1 || Find(match[v]))
            {
                match[v] = x;
                tag[x] = v;
                return true;
            }
        }
        return false;
    }
    int HK()
    {
        memset(tag,-1,sizeof(tag));
        memset(match,-1,sizeof(match));
        int ans = 0;
        while(bfs())
        {
            memset(vis,0,sizeof(vis));
            for(int i = 1;i <= cnt1;++i) if(tag[i] == -1 && Find(i)) ans++;
        }
        return ans;
    }
    int main()
    {
        int ca;ca = read();
        while(ca--)
        {
            n = read();
            unordered_map<int,int> mp1,mp2;
            cnt1 = 0,cnt2 = 0;
            for(int i = 1;i <= n;++i) G[i].clear();
            for(rg int i = 1;i <= n;++i)
            {
                int t,x;t = read(),x = read();
                if(mp1[x+t] == 0) mp1[x+t] = ++cnt1;
                if(mp2[x-t] == 0) mp2[x-t] = ++cnt2;
                G[mp1[x+t]].push_back(mp2[x-t]);
            }
            printf("%d\n",HK());
        }
        system("pause");
        return 0;
    }
    View Code

    Contest of Rope Pulling

    1:歪解:

    对两组的人进行01背包。

    因为要人数相等才能减到1,所以上界只需要两组人总和较小的。

    然后从0开始动态维护上界。最坏复杂度5e8左右。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef long double ld;
    typedef pair<LL,int> pii;
    const int N = 1e3+5;
    const int M = 1e6+5;
    const LL Mod = 1e9+7;
    #define rg register
    #define pi acos(-1)
    #define INF 1e18
    #define INM INT_MIN
    #define dbg(ax) cout << "now this num is " << ax << endl;
    inline LL read()
    {
        LL x = 0,f = 1;char c = getchar();
        while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
        return x*f;
    }
    LL w1[1005],v1[1005],w2[1005],v2[1005];
    LL dp1[M],dp2[M];
    int main()
    {
        int ca;ca = read();
        while(ca--)
        {
            int n,m;n = read(),m = read();
            int ma1 = 0,ma2 = 0;
            for(int i = 1;i <= n;++i)
            {
                w1[i] = read(),v1[i] = read();
                ma1 += w1[i];
            }
            for(int i = 1;i <= m;++i)
            {
                w2[i] = read(),v2[i] = read();
                ma2 += w2[i];
            }
            int up = min(ma1,ma2);
            for(int i = 0;i <= up;++i) dp1[i] = dp2[i] = -INF;
            dp1[0] = dp2[0] = 0;
            int tmp1 = 0,tmp2 = 0;
            for(int i = 1;i <= n;++i)
            {
                tmp1 += w1[i];
                for(int j = min(tmp1,up);j >= w1[i];--j) dp1[j] = max(dp1[j],dp1[j-w1[i]]+v1[i]);
            }
            for(int i = 1;i <= m;++i)
            {
                tmp2 += w2[i];
                for(int j = min(tmp2,up);j >= w2[i];--j) dp2[j] = max(dp2[j],dp2[j-w2[i]]+v2[i]);
            }
            LL ans = -INF;
            for(int i = 0;i <= up;++i) ans = max(ans,dp1[i]+dp2[i]);
            printf("%lld\n",ans);
        }
        system("pause");
        return 0;
    }
    View Code

    2:正解:

    那么,考虑到两组人要w的权值相同。

    那么我们可以对第二组人的w取反。

    那么第一组人的w值肯定为正,第二组人的w值肯定为负。

    那么题目就变成了,找出部分人,w的总和相加为0时,v的最大总值。

    我们随机化所有人的位置。来保证w的前缀和一直在0左右浮动,不让这个值过大。

    然后就可以进行01背包,以某个数据为中值(这里为40000)作为0的替代点,进行dp

    但是这里有点看脸,反正随机了蛮多次都拉胯了

    View Code
  • 相关阅读:
    SpringMVC
    spring-02
    spring-01
    适配器模式
    状态模式
    抽象工厂模式
    观察者模式(发布-订阅模式)
    建造者模式(生成器模式)
    外观模式
    迪米特法则
  • 原文地址:https://www.cnblogs.com/zwjzwj/p/13407814.html
Copyright © 2020-2023  润新知