• 2021"MINIEYE杯"中超(3)补题


    2021"MINIEYE杯"中超(3)

    1003 Forgiving Matching

    还在努力看fft,还不会做。。。。

    1004 Game on Plane

    首先两条直线存在交点当且仅当两条直线斜率不同,所以Alice的最优策略就是最小化斜率出现次数最多的数目,Bob的最优策略就是画一条斜率是出现次数最多的斜率的直线。所以Alice策略就是不断从各种斜率的直线中各取一条即可。

    记住特判一下斜率不存在和斜率是负数的负号归属的情况,还有因为存的是(y2 - y1) / (x2 - x1),存的时候还要将其化简。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    typedef pair<int, int> PII;
    
    int t;
    int n;
    
    int gcd(int a, int b)
    {
        return b ? gcd(b, a % b) : a;
    }
    
    void solve()
    {
        map<PII, int> m;
        int x1, x2, y1, y2;//莫名其妙这一句放到全局变量就报错。。。
        cin >> n;
        for (int i = 1; i <= n; i ++ )
        {
            cin >> x1 >> y1 >> x2 >> y2;
            int x = x2 - x1, y = y2 - y1;
            bool flag = ((x < 0) ^ (y < 0));
            
            if (x < 0) x = -x; 
            if (y < 0) y = -y;
            if (flag) x = -x;//如果斜率是负的,为方便统计把负号放在x的位置
            
            PII temp;
            if (x == 0)//斜率不存在
                temp = make_pair(0, 1);
            else if (y == 0)//斜率为0
                temp = make_pair(1, 0);
            else
            {
                int u = gcd(x, y);
                temp = make_pair(x / u, y / u);//约分
            }
            
            if (!m[temp]) m[temp] = 1; else m[temp] ++ ;//统计个数
        }
        
        vector<int> v;
        for (map<PII, int>::iterator it = m.begin(); it != m.end(); it ++ ) v.push_back(it -> second);
        sort(v.begin(), v.end(), greater<int>());//从大到小排序
        //for (auto t : v) cout << t << ' '; cout << endl;
        
        int len = v.size();//cout << len << endl;
        int ans = 0;
        int pos = 0;
        for (int i = 1; i <= n; i ++ )
        {
            if (!v[pos] || pos == len) pos = 0, ans ++ ;//如果有一种用光了或者每一种都用过了,那么必定要重复
            printf("%d
    ", i - ans - 1);
            v[pos] -- ;
            pos ++ ;
        }
    }
    
    int main()
    {
        ios::sync_with_stdio(0);cin.tie(0);
        cin >> t;
        while (t -- ) solve();
        
        return 0;
    }
    
    1009 Rise in Price

    题目大意:从(1, 1)走到(n, n),取走路径上的所有数,求(∑a_i_j) * (∑b_i_j)的最大值。首先考虑dpf[i, j, k]表示走到了[i, j]点,拿了k个钻石,此时价格上涨了f[i, j, k],但是由于k取值过大,dp空间不够。所以不可以用这种常规的dp。

    接着考虑,dp的每个状态都存的是每种情况的最优解,所以才导致空间使用过大,换种思路,[i, j]这个点的状态取决于[i - 1, j]和[i, j - 1],我们从中一定是取比较优的状态,所以我们每个位置开一个vector,从前面的位置继承状态后根据本题要求按照优劣排序,储存一部分状态,然后择优继承,局部最优来达到全局最优。

    注意事项:1.开longlong 2.每次都要clear一下vector 3.不要用for(auto)赋值!因为这个错误debug了好久。。。

    #include <bits/stdc++.h>
    
    #define x first
    #define y second
    
    using namespace std;
    
    typedef long long LL;
    typedef pair<LL, LL> PLL;
    
    const int N = 110;
    
    vector<PLL> v[N][N];
    int t;
    int n;
    LL a[N][N], b[N][N];
    
    bool cmp(PLL a, PLL b)
    {
        return a.x * a.y > b.x * b.y;
    }
    
    void solve()
    {
        cin >> n;
        for (int i = 1; i <= n; i ++ )
            for (int j = 1; j <= n; j ++ )
            {
                cin >> a[i][j];
                v[i][j].clear();
            }
        for (int i = 1; i <= n; i ++ )
            for (int j = 1; j <= n; j ++ )
                cin >> b[i][j];
        
        //for (int i = 1; i <= n; i ++ ) for (int j = 1; j <= n; j ++ ) cout << a[i][j] << (j == n ? '
    ' : ' ');
        //for (int i = 1; i <= n; i ++ ) for (int j = 1; j <= n; j ++ ) cout << b[i][j] << (j == n ? '
    ' : ' ');
        for (int i = 1; i <= n; i ++ )
            for (int j = 1; j <= n; j ++ )
            {
                if (i == 1 && j == 1)//左上角直接继承自己
                {
                    v[i][j].push_back(make_pair(a[i][j], b[i][j]));
                    continue;
                }
                else if (i == 1) v[i][j].push_back(v[i][j - 1][0]);
                else if (j == 1) v[i][j].push_back(v[i - 1][j][0]);
                else
                {
                    int p1 = 0, p2 = 0;//指针
                    while (v[i][j].size() < 100)//取大概100个状态择优转移
                    {
                        if (p1 < v[i - 1][j].size() && p2 < v[i][j - 1].size())//两个状态都还可以转移
                        {
                            if (v[i - 1][j][p1].x * v[i - 1][j][p1].y > v[i][j - 1][p2].x * v[i][j - 1][p2].y)//择优
                            {
                                v[i][j].push_back(v[i - 1][j][p1]);
                                p1 ++ ;
                            }
                            else v[i][j].push_back(v[i][j - 1][p2]), p2 ++ ;
                        }
                        else if (p1 < v[i - 1][j].size())//扫尾
                        {
                            v[i][j].push_back(v[i - 1][j][p1]);
                            p1 ++ ;
                        }
                        else if (p2 < v[i][j - 1].size())
                        {
                            v[i][j].push_back(v[i][j - 1][p2]);
                            p2 ++ ;
                        }
                        else break;//都继承完了
                    }
                }
                
                for (int k = 0; k < v[i][j].size(); k ++ ) v[i][j][k].x += a[i][j], v[i][j][k].y += b[i][j];//加上当前格子的值
                //for (auto t : v[i][j]) t.x += a[i][j], t.y += b[i][j];//这种写法错误,值并没有赋过去!!!
                sort(v[i][j].begin(), v[i][j].end(), cmp);//根据优劣排序
            }
        
        cout << v[n][n][0].x * v[n][n][0].y << endl;
    }
    
    int main()
    {
        ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
        cin >> t;
        while (t -- ) solve();
        
        return 0;
    }
    
    
    1011 Segment Tree with Pruning

    线段树最多有log种长度,所以直接记忆化搜索就行。要注意每次都要把map清空。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long LL;
    
    int t;
    LL n, k;
    map<LL, LL> m;
    
    LL build(LL l, LL r) 
    {
        if (m.count(r - l)) return m[r - l];//如果这个段已经计算过了,不用再计算,直接返回
        if (r - l + 1 <= k) return 1;//区间不可以再分了
        LL mid = l + r >> 1, cnt = 1;
        cnt += build(l, mid) + build(mid + 1, r);
        return m[r - l] = cnt;
    }
    
    int main()
    {
        ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
        cin >> t;
        while (t -- )
        {
            cin >> n >> k;
            m.clear();//清空map
            cout << build(1, n) << endl;
        }
        
        return 0;
    }
    
    
  • 相关阅读:
    Python 函数 -range()
    Python 函数 -xrange()
    Python 函数 -globals()
    Python 函数-max()
    Python 函数 -hasattr()
    Python 函数 memoryview()
    Python函数 hash()
    QAQ
    Õ() Big-O-notation
    一道有趣的条件概率题
  • 原文地址:https://www.cnblogs.com/scl0725/p/15094890.html
Copyright © 2020-2023  润新知