NOIP2013 재생

NOIP2013 재생

D1T1 P1965 돌고 게임

물어에 \ (X + m \ 시간 10 ^ K \) 막 \ (\ N-) 의 값.

KSM 템플릿입니다.

D1T2 P1966은 일치하는 줄

\ (\ SUM (a_ib_i) = A_I ^ 2 ^ 2 + b_i ^ 2-2a_ib_i \) , 상관 제곱 용어 행이 증가 될 필요가없는 방법이다 (a_ib_i \) \ 이.

그것은 재 배열 불평등으로 알려져 있습니다 : 가까이 두 숫자, 더 큰 값.

그래서해야 \ (A \) 배열과 \의 (b \) 이 가장 큰이며, 해당 다음, 배열은 분류되어 있습니다.

이제 문제는 방법이다 \ (A \) 그림의 크기 관계가된다 \ (b \) ?

구체적인 수치는 크기에 영향을 미치는, 그래서 우리 모두 이산 때문입니다.

확인 \ (c를 [A [내가] = (B)는 [I]는 \) , 가장 대답하자 경우 \ (c [A [I] = A [i]는 \) 이다 \ (c [i]를 I = \) .

그것은된다 (C \) \ 어레이로부터해진다 \ (1 \) 받는 \ N- (\) 배열의 최소 동작.

맞아 반전되지 않는 이유는 무엇입니까? 펜윅 트리 나는 일종의 쓰기 시작 병합.

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 100005, mod = 99999997;
int a[maxn], b[maxn], c[maxn], d[maxn], q[maxn], t[maxn], ans;
int n;
bool cmp1(int x, int y)
{
    return a[x] < a[y];
}
bool cmp2(int x, int y)
{
    return b[x] < b[y];
}
int read()
{
    int ans = 0, s = 1;
    char ch = getchar();
    while(ch > '9' || ch < '0')
    {
        if(ch == '-') s = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        ans = ans * 10 + ch - '0';
        ch = getchar();
    }
    return s * ans;
}
void msort(int l, int r)
{
    int mid = (l + r) >> 1;
    if(l != r) msort(l, mid), msort(mid + 1, r);
    int i = l, j = mid + 1, k = l;
    while(i <= mid && j <= r)
    {
        if(q[i] > q[j])
        {
            ans = (ans + j - k) % mod;
            t[k++] = q[j++];
        }
        else t[k++] = q[i++];
    }
    while(i <= mid) t[k++] = q[i++];
    while(j <= r) t[k++] = q[j++];
    for(int i = l; i <= r; i++) q[i] = t[i];
}
int main()
{
    n = read();
    for(int i = 1; i <= n; i++)
    {
        a[i] = read();
        c[i] = i;
    }
    for(int i = 1; i <= n; i++)
    {
        b[i] = read();
        d[i] = i;
    }
    sort(c + 1, c + 1 + n, cmp1);
    sort(d + 1, d + 1 + n, cmp2);
    for(int i = 1; i <= n; i++) q[c[i]] = d[i];
    msort(1, n);
    printf("%d\n", ans);
    return 0;
}

D1T3 P1967의 트럭

이 그래프 최대 스패닝 트리의 측면 될 것입니다 각면을 통해 (추측) 증명, 또는 당신은 잃게됩니다 어렵지 않다.

그래서, 최대 스패닝 트리를주고이를 변경 크루스 칼 관행을 기호를 사용합니다.

다음에, 기본적인 최소 경로 트리되고, 트리를 이용하여 단면 세그먼트 트리가 유지 될 수있다.

이 질문은 또한 폭력 점프 LCA 아를 끌 수 있습니다. . .

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 10005, maxm = 50005, INF = 19260817;
int n, m, q;
//kruskal
struct edge
{
    int u, v, w;
} ee[maxm];
int f[maxn];
//new graph
struct Edge
{
    int next, to, weight;
} e[maxm << 1];
int head[maxn], etot;
//shupou
int dep[maxn], size[maxn], wson[maxn], fa[maxn];
int top[maxn], dfn[maxn], pre[maxn], dtot;
int path[maxn];
//functions
int read()
{
    int ans = 0, s = 1;
    char ch = getchar();
    while(ch > '9' || ch < '0')
    {
        if(ch == '-') s = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        ans = ans * 10 + ch - '0';
        ch = getchar();
    }
    return s * ans;
}
int find(int x)
{
    if(f[x] == x) return x;
    return f[x] = find(f[x]);
}
bool cmp(const edge x, const edge y)
{
    return x.w > y.w;
}
void link(int u, int v, int w)
{
    e[++etot] = (Edge){head[u], v, w};
    head[u] = etot;
}
void kruskal()
{
    for(int i = 1; i <= n; i++) f[i] = i;
    sort(ee + 1, ee + m + 1, cmp);
    for(int i = 1; i <= m; i++)
    {
        int x = find(ee[i].u), y = find(ee[i].v), w = ee[i].w;
        if(x != y)
        {
            link(x, y, w); link(y, x, w);
            f[x] = y;
        }
    }
}
void dfs1(int u, int ff, int w)
{
    size[u] = 1; fa[u] = ff; dep[u] = dep[ff] + 1; path[u] = w;
    for(int i = head[u]; i; i = e[i].next)
    {
        int v = e[i].to;
        if(v == ff) continue;
        dfs1(v, u, e[i].weight);
        size[u] += size[v];
        if(size[v] > size[wson[u]]) wson[u] = v;
    }
}
void dfs2(int u, int topf)
{
    dfn[u] = ++dtot; pre[dtot] = u; top[u] = topf;
    if(wson[u]) dfs2(wson[u], topf);
    for(int i = head[u]; i; i = e[i].next)
    {
        int v = e[i].to;
        if(v == fa[u] || v == wson[u]) continue;
        dfs2(v, v);
    }
}
int getlca(int u, int v)
{
    if(find(u) != find(v)) return -1;
    while(top[u] != top[v])
    {
        if(dep[top[u]] < dep[top[v]]) swap(u, v);
        u = fa[top[u]];
    }
    if(dep[u] > dep[v]) swap(u, v);
    return u; 
}
int getans(int u, int v, int lca)
{
    if(lca == -1) return -1;
    int ans = INF;
    while(u != lca)
    {
        ans = min(ans, path[u]);
        u = fa[u];
    }
    while(v != lca)
    {
        ans = min(ans, path[v]);
        v = fa[v];
    }
    return ans;
}
int main()
{
    n = read(), m = read();
    for(int i = 1; i <= m; i++)
    {
        ee[i] = (edge){read(), read(), read()};
    }
    kruskal();
    for(int i = 1; i <= n; i++)
    {
        if(dep[i] == 0)
        {
            dfs1(i, 0, 0); dfs2(i, i);
        }
    }
    q = read();
    while(q--)
    {
        int x = read(), y = read();
        printf("%d\n", getans(x, y, getlca(x, y)));
    }
    return 0;
}

D2T1 P1969 빌딩 대회

NOIP2018 원래 제목을 기념하지만, 불행히도 나는하지 않았다

분할 정복 방법은 카드가 될 수있다 \ (O합니다 () ^ 2 N- \) , 포지티브 용액 실제로 \ (O (N) \) 재발.

세트 \는 (ANS는 [I]는 \) 전방에있다 \ (I는 \) 않음 번째 각 순회 얻어진다 \ (I는 \) 두 가지 경우 :

  1. \ (A [I]가 \ 당량 A가 [-I. 1] \) 의 팽창 영역의 전면에 추가 만 방법을 필요로하지 않는다. 즉,이 대답의 앞에 상속됩니다.
  2. \ (A [I]> = A [I-. (1)] \) , 다음 추가로 필요 \을 (A [i]를 -a [ I-1] \) 이 일 작성 작업.

완성 된 2 예 작성 작업이 계산되어 있기 때문에 이러한 행위는 설립되었습니다.

D2T2 P1970 정원사

이 질문은 하나의 DP이고, 하나는 욕심 형이상학, ​​두 개의 솔루션을 제공합니다.

방법은 DP를 구비 \을 (최대 [I] \)\ (아래 [I] \) 의 기록 전에 \ (I \) 번째 현재 최대 시퀀스 길이하여 상승 또는 하강된다.

당신이 증가 얻을 경우, 같은 이유로 감소, n은 플러스 1 방울의 최대 길이에서 꺼낸다.

업데이트하지 않으면 동시에, 이전의 최대 길이는 상속 될 수 있습니다.

코드 청 치 :

#include<cstdio>
using namespace std;
const int maxn = 100005;
inline int max(int a, int b)
{
    if(a > b) return a;
    return b;
}
int a[maxn], up[maxn], down[maxn];
int n;
int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
    up[1] = down[1] = 1;
    for(int i = 2; i <= n; i++)
    {
        if(a[i - 1] < a[i]) up[i] = down[i - 1] + 1;
        else up[i] = up[i - 1];
        if(a[i - 1] > a[i]) down[i] = up[i - 1] + 1;
        else down[i] = down[i - 1];
    }
    printf("%d\n", max(up[n], down[n]));
    return 0;
}

형이상학 욕심 접근 방식은 이것이다 :

#include<bits/stdc++.h>
using namespace std;
int n,h[1000005],ans=1;bool con;
int main()
{
    cin>>n;for(int i=1;i<=n;i++) cin>>h[i];
    if(h[2]>=h[1]) con=1;
    for(int i=1;i<=n;i++)
    {
        if(con==0&&i==n) {ans++;break;}
        if(con==1) if(h[i+1]<h[i]){ans++;con=0;continue;}
        if(con==0) if(h[i+1]>h[i]) {ans++;con=1;continue;}
    }
    cout<<ans; 
}

제 1 및 제 2 결정 방향을 결정을 통해, 그 후 일정하게 증가하거나 마지막을 감소 분명히 응답은 최적이다.

그 단계 ANS는 ++ 정말 좋지 않다.

이 코드는 데이터 카드의 복수를 반복 할 수 있지만,이 질문에 데이터를 균일 난수를 배포됩니다.

D2T3 P1979 화용

https://www.luogu.org/blog/moisture2333/solution-p1979w

#include<bits/stdc++.h>
const int maxn = 31;
const int INF = 0x3f3f3f3f;
const int dx[] = {-1, 1, 0, 0};
const int dy[] = {0, 0, -1, 1};
int n, m, Q;
int ex, ey, bx, by, cx, cy;
int G[maxn][maxn];
bool vis[maxn][maxn];
bool ok[maxn][maxn][4];

struct Edges {
    int next, to, weight;
} e[200005];
int head[10005], tot;
bool visit[10005];
int dist[10005];
void link(int u, int v, int w) {
    e[++tot] = (Edges){head[u], v, w};
    head[u] = tot;
}
int getid(int x, int y, int dir) {
    return 4 * ((x - 1) * m + y) - 4 + dir;
}
int query(int x, int y) {
    if(x < 1 || x > n || y < 1 || y > m) return 0;
    return G[x][y];
}
int bfs(int nx, int ny, int sx, int sy, int tx, int ty) {
    // ¿Õ°×¸ñ×ÓÂÒת ¶øÄ¿±êÆå×Ó²»Òƶ¯ 
    struct Nodes {
        int x, y, dis;
    };
    std::queue<Nodes> q;
    memset(vis, false, sizeof vis);
    q.push((Nodes){sx, sy, 0}); vis[sx][sy] = true;
    while(!q.empty()) {
        Nodes sb = q.front(); q.pop();
        if(sb.x == tx && sb.y == ty) return sb.dis;
        for(int i = 0; i < 4; i++) {
            int newx = sb.x + dx[i], newy = sb.y + dy[i];
            if(query(newx, newy)) {
                if(vis[newx][newy]) continue;
                if(newx == nx && newy == ny) continue;
                q.push((Nodes){newx, newy, sb.dis + 1}); vis[newx][newy] = true;
            }
        }
    }
    return INF;
}
void init() {
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            if(!G[i][j]) continue;
            for(int k = 0; k < 4; k++) {
                if(query(i + dx[k], j + dy[k])) ok[i][j][k] = true;
            }
        }
    }
    
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            for(int k = 0; k < 4; k++) {
                for(int l = k + 1; l < 4; l++) {
                    if(ok[i][j][k] && ok[i][j][l]) {
                        int a = getid(i, j, k), b = getid(i, j, l);
                        int temp = bfs(i, j, i + dx[k], j + dy[k], i + dx[l], j + dy[l]);
                        if(temp == INF) continue;
                        link(a, b, temp); link(b, a, temp);
                    }
                }
            }
        }
    }
    
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j < m; j++) {
            if(ok[i][j][3] && ok[i][j + 1][2]) {
                int a = getid(i, j, 3), b = getid(i, j + 1, 2);
                link(a, b, 1); link(b, a, 1);
            }
        }
    }
    for(int i = 1; i < n; i++) {
        for(int j = 1; j <= m; j++) {
            if(ok[i][j][1] && ok[i + 1][j][0]) {
                int a = getid(i, j, 1), b = getid(i + 1, j, 0);
                link(a, b, 1); link(b, a, 1);
            }
        }
    }
}
void solve() {
    std::queue<int> q;
    memset(dist, 0x3f, sizeof dist);
    for(int i = 0; i < 4; i++) {
        int newx = bx + dx[i], newy = by + dy[i];
        if(query(newx, newy)) {
            int temp = bfs(bx, by, ex, ey, newx, newy);
            if(temp == INF) continue;
            int idx = getid(bx, by, i);
            dist[idx] = temp;
            q.push(idx); visit[idx] = true;
        }
    }
    while(!q.empty()) {
        int u = q.front(); q.pop(); visit[u] = false;
        for(int i = head[u]; i; i = e[i].next) {
            int v = e[i].to;
            if(dist[v] > dist[u] + e[i].weight) {
                dist[v] = dist[u] + e[i].weight;
                if(!visit[v]) {
                    q.push(v); visit[v] = true;
                }
            }
        }
    }
    int ans = INF;
    for(int i = 0; i < 4; i++) {
        int temp = getid(cx, cy, i);
        ans = std::min(ans, dist[temp]);
    }
    if(ans == INF) printf("-1\n");
    else printf("%d\n", ans);
}
int main() {
    scanf("%d %d %d", &n, &m, &Q);
    for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) scanf("%d", &G[i][j]);
    init();
    while(Q--) {
        scanf("%d %d %d %d %d %d", &ex, &ey, &bx, &by, &cx, &cy);
        if(bx == cx && by == cy) {
            printf("0\n");
        } else if(!G[cx][cy] || !G[bx][by]) {
            printf("-1\n");
        } else solve();
    }
    return 0;
}

추천

출처www.cnblogs.com/Garen-Wang/p/11619073.html