夏休みN天楽【試合編】――2019杭州電夏期多校訓練キャンプ(第六回)

12214 ワード

胡漢三はまた転びました。賞味期限が過ぎた問題もメモしてください。
以下の問題は以下の通りです。
\[1002[HU-635]\1005【HU-6368】\1006【HU-639】\1008【HU-641】\1012【HDU-645】
【1002】LIS+暴力HU-6365 Nonsense Time
http://acm.hdu.edu.cn/showproblem.php?pid=6635
参考:https://blog.csdn.net/henuyh/article/details/98845165
長さが「(n\)の2つの配列\(a,b\)を指定して、\(a\)の下に「(bui\)と表示されている数字は現在利用可能です。\(b ui\)に対応する\(a\)のLISを求めて、\(a\)の中に\(1,n)\)の全配列です。
データがランダムに生成されるので、LISの期待長さは\(\sqrt{n}\)であり、削除要素がLISにある確率は\(\\fraac{1}{\sqrt{n})であるため、全体の複雑度:\(o(n\sqrt{n}log(n)))である。先にすべてのLISを解いて、その後から前へ配列\(b\)を遍歴して、削除した要素がLISの中でもう一度求めます。LISの経路を記録する必要があります。
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;

const int maxn = 5e4+5;

int n;
int a[maxn];
int b[maxn];
int vis[maxn];
int ans[maxn];
int temp[maxn];
int path[maxn];
int used[maxn];

int solve() {
    int len = 0;
    for(int i = 1; i <= n; i++) {
        if(vis[a[i]] == 1) {
            continue;
        }
        int x = lower_bound(temp, temp+len, a[i]) - temp;
        if(x == len) {
            temp[len++] = a[i];
            path[i] = len;
        }
        else {
            temp[x] = a[i];
            path[i] = x + 1;
        }
    }
    memset(used, 0, sizeof(used));
    int x = len;
    for(int i = n; i >= 1; i--) {
        if(vis[a[i]] == 1) {
            continue;
        }
        if(path[i] == x) {
            used[a[i]] = 1;
            x--;
        }
    }
    return len;
}

int main() {
    int t;
    scanf("%d", &t);
    while(t--) {
        memset(vis, 0, sizeof(vis));
        scanf("%d", &n);
        for(int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
        }
        for(int i = 1; i <= n; i++) {
            scanf("%d", &b[i]);
        }
        ans[n] = solve();
        for(int i = n-1; i >= 1; i--) {
            vis[a[b[i+1]]] = 1;
            if(used[a[b[i+1]]] == 0) {
                ans[i] = ans[i+1];
            }
            else {
                ans[i] = solve();
            }
        }
        for(int i = 1; i <= n; i++) {
            printf("%d%c", ans[i], i==n?'
':' '); } } return 0; }
【1005】線分樹HU-6368 Snowy Smile
http://acm.hdu.edu.cn/showproblem.php?pid=6638
参考:https://blog.csdn.net/A_Thinking_Reed_/アート/detail/98778260
与えられた\(n(\leq 2000)\の点座標と対応する権利値は、最大の重みと行列を求める。
上下境界を列挙するたびに、線分樹に加点し、上下境界内の最大サブセグメントと「区間最大サブセグメントと」を維持します。境界上を移動する時、複数の点が現在の直線上にあります。同じように、境界上のすべての点を更新してから更新できます。
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;

const int maxn = 2e3+5;

struct node{
    int x, y;
    ll val;
    bool operator < (const node &q) const {
        if(y == q.y) {
            return x < q.x;
        }
        return y > q.y;
    }
}p[maxn];

struct NODE {
    ll sum, lsum, rsum, maxsum;
}T[maxn << 2];

int n; 
vector vx, vy;

int get_xid(int x) {
    return lower_bound(vx.begin(), vx.end(), x) - vx.begin() + 1;
}

int get_yid(int y) {
    return lower_bound(vy.begin(), vy.end(), y) - vy.begin() + 1;
}

void pushup(int rt) {
    T[rt].sum = T[rt<<1].sum + T[rt<<1|1].sum;
    T[rt].lsum = max(T[rt<<1].lsum, T[rt<<1].sum + T[rt<<1|1].lsum);
    T[rt].rsum = max(T[rt<<1|1].rsum, T[rt<<1|1].sum + T[rt<<1].rsum);
    T[rt].maxsum = max(T[rt<<1].rsum+T[rt<<1|1].lsum, max(T[rt<<1].maxsum, T[rt<<1|1].maxsum));
}

void build(int l, int r, int rt) {
    T[rt].sum = T[rt].lsum = T[rt].rsum = T[rt].maxsum = 0;
    if(l == r) {
        return ;
    }
    int mid = (l+r) >> 1;
    build(l, mid, rt<<1);
    build(mid+1, r, rt<<1|1);
    pushup(rt);
}

void update(int l, int r, int pos, int val, int rt) {
    if(l == r) {
        T[rt].sum = T[rt].lsum = T[rt].rsum = T[rt].maxsum = T[rt].sum+val;
        return ;
    }
    int mid = (l+r) >> 1;
    if(pos <= mid) {
        update(l, mid, pos, val, rt<<1);
    }
    else {
        update(mid+1, r, pos, val, rt<<1|1);
    }
    pushup(rt);
}

int main() {
    int t;
    scanf("%d", &t);
    while(t--) {
        vx.clear();
        vy.clear();
        scanf("%d", &n);
        for(int i = 1; i <= n; i++) {
            scanf("%d%d%lld", &p[i].x, &p[i].y, &p[i].val);
            vx.push_back(p[i].x);
            vy.push_back(p[i].y);
        }
        sort(vx.begin(), vx.end());
        vx.erase(unique(vx.begin(), vx.end()), vx.end());
        sort(vy.begin(), vy.end());
        vy.erase(unique(vy.begin(), vy.end()), vy.end());
        int new_n = vx.size();
        for(int i = 1; i <= n; i++) {
            p[i].x = get_xid(p[i].x);
            p[i].y = get_yid(p[i].y);
        }
        sort(p+1, p+1+n);
        ll ans = 0;
        int lst_y = -1;
        for(int i = 1; i <= n; i++) {
            if(lst_y == p[i].y) {
                continue;
            }
            build(1, new_n, 1);
            for(int j = i; j <= n; ) {
                int k;
                for(k = j; k <= n && p[k].y == p[j].y; k++) {
                    update(1, new_n, p[k].x, p[k].val, 1);
                }
                ans = max(ans, T[1].maxsum);
                j = k;
            }
            lst_y = p[i].y;
        }
        printf("%lld
", ans); } return 0; }
【1006】思惟HU-6369 Faraway
http://acm.hdu.edu.cn/showproblem.php?pid=6639
二次元の座標点(兵士)があります。彼らは共通の目的地を持っています。(x_{e}、y_{e}\)、知っています。(xue\)も\(yuue\)も範囲内にいると知っていますが、彼らは自分の位置しか知らないです。)\%k_{i}=t_{i}\今あなたにいくつの可能な目標があるか聞いてみます。
の絶対値を取り外すと、各点\((xui,yui)\)は平面を4つの部分に分割して、合計\(n^2\)の領域になります。各エリアを列挙して、そのエリア内の可能な終点の数を計算します。"(lcm(2,3,4,5)=60\)ですので、列挙\(xue\)と\(yue\)モデル60の余りが必要です。\(o(n)\)は実行可能かどうかを判断します。
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;

int n, m;
vector vx, vy;

struct node {
    int x, y;
    int k, t;
}p[15];

int check(int a, int b) {
    for(int i = 1; i <= n; i++) {
        if((abs(a-p[i].x)+abs(b-p[i].y))%p[i].k != p[i].t) {
            return 0;
        }
    }
    return 1;
}

int cal(int x, int y) {
    if(y-x-1 < 0) {
        return 0;
    }
    return ((y-x-1)/60) + 1; 
}

int main() {
    int t;
    scanf("%d", &t);
    while(t--) {
        vx.clear();
        vy.clear();
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; i++) {
            scanf("%d%d%d%d", &p[i].x, &p[i].y, &p[i].k, &p[i].t);
            vx.push_back(p[i].x);
            vy.push_back(p[i].y);
        }
        vx.push_back(0);
        vx.push_back(m+1);
        vy.push_back(0);
        vy.push_back(m+1);
        sort(vx.begin(), vx.end());
        vx.erase(unique(vx.begin(), vx.end()), vx.end());
        int nx = vx.size();
        sort(vy.begin(), vy.end());
        vy.erase(unique(vy.begin(), vy.end()), vy.end());
        int ny = vy.size();
        ll ans = 0;
        for(int i = 0; i < nx-1; i++) {
            for(int j = 0; j < ny-1; j++) {
                for(int k = 0; k < 60; k++) {
                    for(int l = 0; l < 60; l++) {
                        if(check(vx[i]+k, vy[j]+l)) {
                            ans += 1ll*cal(vx[i]+k, vx[i+1])*cal(vy[j]+l, vy[j+1]);
                        }
                    }
                }
            }
        }
        printf("%lld
", ans); } return 0; }
【1008】数学HU-641 TDL
http://acm.hdu.edu.cn/showproblem.php?pid=6641
チームメイトが書いたのはソースです。
#include
#include
#include
#include
#include
#include
#define lson node<<1
#define rson node<<1|1
using namespace std;
typedef long long ll;

const ll inf = 2e18;
const ll mod = 998244353;
const int maxn = 1e5 + 20;


ll gcd(ll a, ll b) {
    return b == 0 ? a : gcd(b, a % b);
}


int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        ll k, m;
        scanf("%lld%lld", &k, &m);
        ll ans = inf;
        int flag = 0;
        for (int i = 1; i <= 2000; i++) {
            ll n = k ^ i;
            int cnt = 0;
            int j = 1;
            for (; j <= 1000; j++) {
                if (gcd(j + n, n) == 1) {
                    cnt++;
                    if (cnt == m)
                        break;
                }
            }
            if ((n + j) == (i + n)) {
                ans = min(ans, n);
                flag = 1;
            }
        }
        if (flag)
            printf("%lld
", ans); else printf("-1
"); } }
【1012】水題HU-645 permutation 2
http://acm.hdu.edu.cn/showproblem.php?pid=6645
競技の時になぜ位相を書きに行くのか分かりません。
順番を作って、一人で一つずつ分けたらいいです。
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;

int a[100005];

int main() {
    int t;
    scanf("%d", &t);
    while(t--) {
        int n;
        scanf("%d", &n);
        for(int i = 0; i < n; i++) {
            scanf("%d", &a[i]);
        }
        sort(a, a+n);
        ll ans1 = 0, ans2 = 0;
        for(int i = n-1; i >= 0; i-=2) {
            ans1 = ans1 + 1ll*a[i];
        }
        for(int i = n-2; i >= 0; i-=2) {
            ans2 = ans2 + 1ll*a[i];
        }
        printf("%lld %lld
", ans1, ans2); } return 0; }
転載先:https://www.cnblogs.com/Decray/p/11365864.html