ABC224

C

题意:给你一堆不同的点,从中选三个点,能够获得的三角形个数有多少

方法:选三个点,判断是否三点共线,或者用海伦公式判断面积是否为0

#include<iostream>
#include<string>
#include<vector>

using namespace std;

#define int long long

vector<pair<int, int>> v;
int n;

signed main(){
    cin >> n;
    for(int i = 0; i < n; i ++){
        int a, b;
        cin >> a >> b;
        v.push_back({a, b});
    }
    
    int res = 0;
    for(int i = 0; i < n; i ++)
        for(int j = i + 1; j < n; j ++)
            for(int k = j + 1; k < n; k ++){
                int dx0 = v[j].first - v[i].first;
                int dy0 = v[j].second - v[i].second;
                int dx1 = v[k].first - v[j].first;
                int dy1 = v[k].second - v[j].second;
                
                if(dx0 * dy1 != dy0 * dx1) res ++;
            }
                    
    cout << res << endl;
    return 0;
}

D

题意:无向图上的八数码问题

#include<iostream>
#include<string>
#include<vector>
#include<unordered_map>
#include<queue>

using namespace std;

#define int long long

unordered_map<string, int> st;

int m;
vector<int> h[10];
queue<string> q;

signed main(){
    cin >> m;
    while(m --){
        int a, b;
        cin >> a >> b;
        a --, b --;
        h[a].push_back(b);
        h[b].push_back(a);
    }
    
    string s(9, '0');
    for(int i = 1; i <= 8; i ++){
        int a;
        cin >> a;
        a --;
        s[a] = '0' + i;
    }
    
    q.push(s);
    st[s] = 1;
    
    if(s == "123456780"){
        puts("0");
        return 0;
    }
    
    while(q.size()){
        auto s = q.front();
        q.pop();
        
        int e = s.find('0');
        
        for(int i = 0; i < h[e].size(); i ++){
            int j = h[e][i];
            
            string ns = s;
            swap(ns[j], ns[e]);
            
            if(st[ns]) continue;
            
            st[ns] = st[s] + 1;
            q.push(ns);
            
            if(ns == "123456780"){
                cout << st[ns] - 1 << endl;
                return 0;
            }
        }
    }
    
    cout << -1 << endl;
}

E

题意:给你一个网格g,g中有N个点上写了数字,第i个点可以向第j个点走需要满足

  1. (r_i = r_jor c_i = c_j)
  2. (A_i < A_j)

输出从每一个点出发,最多能走的步数

方法:dp

状态:(f(i))表示从第i个点出发能走的最多步数

状态计算:(f(i) = max(f(j) + 1),(r_i = r_jor c_i = c_j)and A_i < A_j)

初始条件:f[1~n] = 0

可以用记忆化,如果用dp,就需要先根据a值升序排序,并且还需要保存每个点的位置,然后倒着转移,此时复杂度为(O(n^2)),N最大为1e5过不了

优化:将所有的点按照a值分成几批,然后根据a值从大到小进行状态转移,维护cmax和rmax,cmax[c]和rmax[r]分别表示第c列上能够转移的最大步数,和第r行上能够转移的最大步数(因为是按照a值从大到小做的,所以如果第r行上有值,就一定是可以转移到的),此时状态转移为(f(i) = max{cmax[point[i].c], rmax(point[i].r))})

并且每一次更新完f(i)还需要更新

[cmax[point[i].c] = max{cmax[point[i].c], f(i) + 1}\ rmax[point[i].r] = max{rmax[point[i].r], f(i) + 1} ]

#include<iostream>
#include<map>
#include<vector>

using namespace std;

int h, w, n;

const int N = 2e5 + 10;

struct node{
    int r, c;
    int i;
};

map<int, vector<node>> m;

int rmax[N], cmax[N];
int f[N];

int main(){
    cin >> h >> w >> n;
    for(int i = 1; i <= n; i ++){
        int r, c, a;
        cin >> r >> c >> a;
        m[a].push_back({r, c, i});
    }
    
    for(auto it = m.rbegin(); it != m.rend(); it ++){
        for(auto t : it->second) f[t.i] = max(cmax[t.c], rmax[t.r]);
        for(auto t : it->second){
            cmax[t.c] = max(cmax[t.c], f[t.i] + 1);
            rmax[t.r] = max(rmax[t.r], f[t.i] + 1);
        }
    }
    
    for(int i = 1; i <= n; i ++) cout << f[i] << endl;
}
原文地址:https://www.cnblogs.com/tomori/p/15450515.html