zoukankan      html  css  js  c++  java
  • AtCoder Regular Contest 097

    传送门

    C - K-th Substring

    题意:
    给出一个字符串,求其第(k)小子串,(kleq 5)

    思路:
    因为(k)很小,所以答案长度不可能超过(k)。所以直接将所有的长度不超过(k)的串拿出来排序就行。

    Code
    #include <bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    // #define Local
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    const int N = 5005;
    
    string s;
    int k;
    vector<string> v;
    
    void run() {
    	v.clear();
    	cin >> s >> k;
    	int len = s.length();
    	for(int i = 1; i <= k; i++) {
    		for(int j = 0; j + i - 1 < len; j++) {
    			v.push_back(s.substr(j, i));
    		}
    	}
    	sort(all(v));
    	unique(all(v));
    	cout << v[k - 1] << '
    ';
    }
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
    #ifdef Local
        freopen("../input.in", "r", stdin);
        freopen("../output.out", "w", stdout);
    #endif
        run();
        return 0;
    }
    
    

    D - Equals

    题意:
    给出一个排列(p),并且给出多个二元组((x_i,y_i)),现在可以执行任意多次操作,每次可以交换(p_{x_i},p_{y_i})
    问最终得到的排列中,(p_i=i)的最大个数是多少。

    思路:
    显然在交换的序列中,处在同一个连通块中的点能到达任意一个位置。
    然后随便搞搞就行。

    Code
    #include <bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    // #define Local
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    const int N = 1e5 + 5;
    
    int n, m;
    int a[N], f[N];
    int pos[N];
    
    int find(int x) {
    	return f[x] == x ? f[x] : f[x] = find(f[x]);
    }
    
    void Union(int x, int y) {
    	int fx = find(x), fy = find(y);
    	if(fx != fy) f[fx] = fy;
    }
    
    std::vector<int> v[N];
    
    void run() {
    	for(int i = 1; i <= n; i++) cin >> a[i];
    	for(int i = 1; i <= n; i++) f[i] = i, v[i].clear();
    	for(int i = 1; i <= m; i++) {
    		int x, y; cin >> x >> y;
    		Union(x, y);
    	}
    	for(int i = 1; i <= n; i++) {
    		pos[i] = find(i);
    		v[find(i)].push_back(a[i]);
    	}
    	int ans = 0;
    	for(int i = 1; i <= n; i++) {
    		for(auto it : v[i]) {
    			if(pos[it] == i) ++ans;
    		}
    	}
    	cout << ans << '
    ';
    }
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
    #ifdef Local
        freopen("../input.in", "r", stdin);
        freopen("../output.out", "w", stdout);
    #endif
        while(cin >> n >> m) run();
        return 0;
    }
    
    

    E - Sorted and Sorted

    题意:
    现在将(n)个白球和(n)个黑球混在一起放置,每种球的标号都是一个排列,每个球都相应有一个(1)(n)的标号。
    现在执行一次操作可以交换相邻两个球的位置,问至少需要多少次操作,最终对于每类球而言,标号都是从小到大(即从(1)(n))。

    思路:

    • 考虑只有一类球时,显然答案为逆序对数。
    • 现在有两类球,这里我们将逆序对给“广义化”。假设我们前面已经放好了(1)(i-1)的白球以及(1)(j)的黑球,我们现在在当前这个位置放置一个白球,此时产生的贡献为(x)(x)表示之前有多少个球在(i)号白球后面,但现在在前面的个数。
    • 这里我理解的就是将逆序对更加广义化,不仅仅是大小关系,这是一种先后关系。
    • 那么我们可以将每个球的贡献利用树状数组预处理出来,之后直接(dp)枚举所有情况来放置就行。

    感觉挺巧妙的,思路僵化还真不好想,但如果想到逐位来放枚举所有情况应该就比较好做了。

    Code
    #include <bits/stdc++.h>
    #define MP make_pair
    #define fi first
    #define se second
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    // #define Local
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    const int N = 2005;
    
    int a[N << 1], c[2][N];
    char s[2];
    int n;
    int cost_w[N][N], cost_b[N][N];
    int dp[N][N];
    
    int lowbit(int x) {return x & (-x);}
    
    void add(int id, int x) {
    	for(; x < N; x += lowbit(x)) ++c[id][x];
    }
    
    int query(int id, int x) {
    	int res = 0;
    	for(; x; x -= lowbit(x)) res += c[id][x];
    	return res;
    }
    
    void run() {
    	memset(c, 0, sizeof(c));
    	for(int i = 1; i <= 2 * n; i++) {
    		cin >> s >> a[i];
    		if(s[0] == 'W') {
    			for(int j = 0; j <= n; j++) {
    				cost_w[a[i] - 1][j] = i - 1 - query(0, a[i] - 1) - query(1, j);
    			}
    			add(0, a[i]);
    		} else {
    			for(int j = 0; j <= n; j++) {
    				cost_b[j][a[i] - 1] = i - 1 - query(1, a[i] - 1) - query(0, j);
    			}
    			add(1, a[i]);
    		}
    	}
    	memset(dp, INF, sizeof(dp));
    	dp[0][0] = 0;
    	for(int i = 0; i <= n; i++) {
    		for(int j = 0; j <= n; j++) {
    			if(i) dp[i][j] = min(dp[i][j], dp[i - 1][j] + cost_w[i - 1][j]);
    			if(j) dp[i][j] = min(dp[i][j], dp[i][j - 1] + cost_b[i][j - 1]);
    		}
    	}
    	cout << dp[n][n] << '
    ';
    }
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
    #ifdef Local
        freopen("../input.in", "r", stdin);
        freopen("../output.out", "w", stdout);
    #endif
        while(cin >> n) run();
        return 0;
    }
    
    

    F - Monochrome Cat

    题意:
    给出一颗树,每个数的结点为黑点或者白点。
    现在当处于一个结点上时有两种选择:

    • 改变当前点的颜色;
    • 走向相邻的一个点,并改变它的颜色。

    最后要求从任意一个起点出发,将整棵树变为黑色的最少操作次数为多少。

    思路:

    • 显然,一个结点所需操作次数跟经过其次数的奇偶性有关。
    • 直接统计不方便统计,我们可以首先将所有“末端”的黑点去掉,那么这颗树的所有叶子结点都为白色,问题就可以转换为子树问题。
    • 显然每条边都会被走两次,但由于起始点的选择不同,可能会存在一条路径只会走一次。
    • 那么先假设每条边都会走两次,最后树(dp)出走一次的路径然后减去即可。

    思路主要就是这样,把冗余的东西减去,问题转换为子树问题,然后状态转移有点繁琐,我就没写代码了(雾)。

  • 相关阅读:
    iphone开发之绘制地图线路
    (ios开发)在MapKit地图上添加注释
    IOS开发地图 (mapkit)实验
    iOS开发之在地图上绘制出你运行的轨迹
    iOS开发之在地图上绘制出你运动的轨迹
    iOS地图位置开发
    IOS开发中的数据库的学习
    Iphone开发 有关 Sqllist的用法
    MapKit
    iphone开发 有关 Navigation Bar 和 UITableView 的用法(代码加说明 呵呵)
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/11726020.html
Copyright © 2011-2022 走看看