2012-2013 ACM-ICPC, NEERC, Central Subregional Contest

A Hanoi Tower 递归

题意:

大家都很熟悉汉诺塔的递归程序,现在给你一个组合,询问你这个组合是否会出现在汉诺塔的递归过程中。

题解:

将汉诺塔的递归程序反过来思考,考虑当前最大的那个盘,我们只会将他从from移动到to,他上面的盘都移动到tmp,那么这个最大的盘一定不会在tmp。如果这个盘在from,说明当前正在进行的过程是将他上面的盘从from移动到tmp,如果这个盘在to,那么说明当前正在进行的过程是将他上面的盘从tmp移动到to。递归下去即可。

代码:

#include<string>
#include<algorithm>
#include<fstream>
using namespace std;

string s;
int n;
bool dfs(char from,char to,char tmp,int i) {
    if (i == n)return true;
    if (s[i] == tmp)return false;
    if (s[i] == from)return dfs(from, tmp, to, i + 1);
    if (s[i] == to)return dfs(tmp, to, from, i + 1);
}

int main() {
    ifstream cin("Input.txt");
    ofstream cout("Output.txt");
    cin.sync_with_stdio(false);
    cin >> n;
    cin >> s;
    reverse(s.begin(), s.end());
    if (s[0] == 'C') {
        cout << "NO" << endl;
        return 0;
    }
    if (dfs('A', 'B', 'C', 0))
        cout << "YES" << endl;
    else
        cout << "NO" << endl;
    return 0;
}
View Code

B Island 模拟

题意:

给你一个加减号组成的图,问你有多少加号与减号相邻。

题解:

直接模拟就好了。

代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <vector>
#include <math.h>
#define INF 0x3f3f3f3f
#define pi 3.141592654

using namespace std;

char str[1001][1001];
int n,m;

int dx[]={0,0,1,-1},dy[]={1,-1,0,0};

bool canmove(int x,int y){
    return x >= 0 && x < n && y >= 0 && y < m;
}

int main() {
    freopen("Input.txt", "r", stdin);
    freopen("Output.txt", "w", stdout);
    while(scanf("%d %d",&n,&m) != EOF){
        for(int i=0;i<n;i++)
            scanf("%s",str[i]);
        int ans = 0;
        for(int i=0;i<n;i++) for(int j=0;j<m;j++) if(str[i][j] == '+'){
            for(int k=0;k<4;k++){
                int nx = i + dx[k];
                int ny = j + dy[k];
                if(canmove(nx,ny) && str[nx][ny] != '+'){
                        ans++;
                       // printf("%d %d
", i, j);
                        break;
                }
            }
        }
        printf("%d
",ans);
    }
    return 0;
}
View Code

C Sequence 打表找规律

题意:

给你一个序列生成器,定义$a[0]=1$,对于$i>0$,$a[i]=sort(a[i-1]*2)$,其中sort是按每一位排序,这个序列的前几项是1,2,4,8,16,23,46,29,58....

现在问你第n项是多少。

题解:

就把序列放到OEIS上,然后就知道规律了。

代码:

#include<cstring>
#include<cstdio>
#include<fstream>
#define MAX_N 50
using namespace std;

long long n;

long long a[MAX_N]={1, 2, 4, 8, 16, 23, 46, 29, 58, 116, 223, 446, 289, 578, 1156, 1223, 2446, 2489, 4789, 5789, 11578, 12356, 12247, 24449, 48889, 77789, 155578, 111356, 122227, 244445};

int main() {
    ifstream cin("Input.txt");
    ofstream cout("Output.txt");
    cin >> n;
    n--;
    if (n < 30)cout << a[n] << endl;
    else cout << a[(n % 6) + 24] << endl;
    return 0;
}
View Code

H Milestones 主席树

题意:

给你一个序列,然后若干次询问,询问从L到R之间有多少不同的值。

题解:

就。。这题是队友做的,貌似就建若干棵主席树,然后搞搞。

代码:

#include <stdio.h>
#include <algorithm>
#include <cstring>
#define maxn 10010

using namespace std;

int tot, a[maxn], cnt;

struct N { int ls, rs, w; } tree[300 * maxn];
int roots[maxn], las[300];

int build_tree(int l, int r) {
    int newnode = tot++;
    tree[newnode].w = 0;
    if (l != r) {
        int mid = (l + r) / 2;
        tree[newnode].ls = build_tree(l, mid);
        tree[newnode].rs = build_tree(mid + 1, r);
    }
    return newnode;
}

int updata(int rt, int pos, int val) {
    int newnode = tot++, tmp = newnode;
    tree[newnode].w = tree[rt].w + val;
    int l = 1, r = cnt;
    while (l < r) {
        int mid = (l + r) / 2;
        if (pos <= mid) {
            tree[newnode].ls = tot++;
            tree[newnode].rs = tree[rt].rs;
            newnode = tree[newnode].ls;
            rt = tree[rt].ls;
            r = mid;
        }
        else {
            tree[newnode].ls = tree[rt].ls;
            tree[newnode].rs = tot++;
            newnode = tree[newnode].rs;
            rt = tree[rt].rs;
            l = mid + 1;
        }
        tree[newnode].w = tree[rt].w + val;
    }
    return tmp;
}

int query(int rt, int k) {
    int l = 1,r = cnt;
    int ans = 0;
    if(k == 0) return tree[rt].w;
    while(l < r){
        int mid = (l + r) / 2;
        if(k <= mid){
            ans += tree[tree[rt].rs].w;
            rt = tree[rt].ls;
            r = mid;
        }
        else{
            rt = tree[rt].rs;
            l = mid + 1;
        }
    }
    return ans;
}

int n, q;

void print(int rt, int l = 1, int r = cnt) {  
    printf("l = %d r = %d w = %d
", l, r, tree[rt].w);
    if (l != r) {  
        int mid = (l + r) / 2;  
        print(tree[rt].ls, l, mid);  
        print(tree[rt].rs, mid + 1, r);  
    }  
}  

int main() {
    freopen("Input.txt", "r", stdin);
    freopen("Output.txt", "w", stdout);
    while (scanf("%d %d", &n, &q) != EOF) {
        for (int i = 1; i <= n; i++)
            scanf("%d", &a[i]);
        cnt = n;
        tot = 0;
        memset(las, -1, sizeof(las));
        roots[0] = build_tree(1, cnt);
        for (int i = 1; i <= n; i++) {
            if (las[a[i]] == -1) {
                roots[i] = updata(roots[i - 1], i, 1);
            }
            else {
                roots[i] = updata(roots[i - 1], las[a[i]], -1);
                roots[i] = updata(roots[i], i, 1);
            }
            las[a[i]] = i;
        }
        int l, r;
        while (q--) {
            scanf("%d %d", &l, &r);
            printf("%d
", query(roots[r], l - 1));
        }
    }
    return 0;
}
View Code

J Computer Network Tarjan+dp

题意:

给你一个图,问你加一条边,使得图的桥的数量减少到最少,输出这条边。

题解:

就Tarjan一发,令桥的权值是1,非桥的权值是0,在Tarjan树上寻找直径即可,整个过程可以在Tarjan的时候dp来完成。令dp[i]表示节点i到其子树的某个叶子的最长路径,然后维护每个点dp的最大和次大值,更新答案即可。

代码:

//#include<iostream>
#include<fstream>
#include<vector>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
#include<set>
#define MAX_N 100004
#define MAX_M 100005
using namespace std;

int dfn[MAX_N],low[MAX_N],ind=0;
bool vis[MAX_N];

int dp[MAX_N];
int pre[MAX_N];
int ans = -1;
int x,y;

struct riGou {
public:
    int u, v, id;

    riGou(int uu, int vv, int i) : u(uu), v(vv), id(i) { }

    riGou() { }

    bool operator<(const riGou &a) const {
        if (u == a.u)
            return v < a.v;
        return u < a.u;
    }
};

struct edge {
public:
    int to, id;

    edge(int t, int i) : to(t), id(i) { }

    edge() { }
};

vector<edge> G[MAX_N];

set<riGou> se;
bool haSame[MAX_N];

void Tarjan(int u,int p) {
    dfn[u] = low[u] = ++ind;
    vis[u] = 1;
    int a = 0, b = 0;
    int nx = u, ny = u;
    for (int i = 0; i < G[u].size(); i++) {
        int v = G[u][i].to;
        if (v == p)continue;
        if (!vis[v]) {
            Tarjan(v, u);
            low[u] = min(low[u], low[v]);
            int ib = 0;
            if (low[v] > dfn[u] && haSame[G[u][i].id] == 0)
                ib = 1;
            if (a <= dp[v] + ib)b = a, a = dp[v] + ib, ny = nx, nx = pre[v];
            else if (b <= dp[v] + ib)b = dp[v] + ib, ny = pre[v];
        }
        else
            low[u] = min(dfn[v], low[u]);
    }
    dp[u] = a;
    pre[u] = nx;
    if (ans < a + b) {
        x = nx, y = ny;
        ans = a + b;
    }
}

int n,m;

int main() {
    ifstream cin("Input.txt");
    ofstream cout("Output.txt");
    cin.sync_with_stdio(false);
    cin >> n >> m;
    for (int i = 0; i < m; i++) {
        int u, v;
        cin >> u >> v;
        riGou a(u, v, i);
        riGou b(v, u, i);
        auto it = se.find(a);
        if (it != se.end()) {
            haSame[it->id] = 1;
            continue;
        }
        it = se.find(b);
        if (it != se.end()) {
            haSame[it->id] = 1;
            continue;
        }
        G[u].push_back(edge(v, i));
        G[v].push_back(edge(u, i));
        se.insert(riGou(u, v, i));
    }
    Tarjan(1, 0);
    if (x == y)
        cout << 1 << " " << n << endl;
    else
        cout << x << " " << y << endl;
    //cout << ans << endl;
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/HarryGuo2012/p/4782558.html