Atcoder Regular 097 相邻球交换目的递增DP
A
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/*Huyyt*/ #include<bits/stdc++.h> #define mem(a,b) memset(a,b,sizeof(a)) #define pb push_back using namespace std; typedef long long ll; typedef unsigned long long ull; const ll LLmaxn = 2e18; string a; int K; string str[10000000]; int pop = 0; map<string, int> mp; int main() { cin >> a; cin >> K; for (int i = 0; i <= 25 && pop < K; i++) { for (int j = 0; j < a.size(); j++) { if (a[j] == 'a' + i) { string now = ""; for (int k = j; k < min((int)a.size(), j + K); k++) { now += a[k]; if (!mp[now]) { str[++pop] = now; //cout<<now<<endl; mp[now]++; } } } } } sort(str + 1, str + pop + 1); cout << str[K] << endl; return 0; }
B
给1-N的一个排列 再给你M个Xi,Yi表示Xi与Yi位置的数可以无限次交换
解:
并查集 因为交换次数是无线的所以在一个集内的数字可以到其他任何一个位置
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/*Huyyt*/ #include<bits/stdc++.h> #define mem(a,b) memset(a,b,sizeof(a)) #define pb push_back using namespace std; typedef long long ll; typedef unsigned long long ull; const ll LLmaxn = 2e18; const int N = 100005; int par[N]; void init(int n) { for (int i = 0; i <= n; i++) { par[i] = i; } } int find(int x) { return par[x] == x ? x : par[x] = find(par[x]); } void unite(int x, int y) { x = find(x); y = find(y); if (x != y) { par[x] = y; } } int num[N]; int where[N]; int a, b; int main() { int n; int m; cin >> n; cin >> m; init(n); int anser = 0; for (int i = 1; i <= n; i++) { cin >> num[i]; where[num[i]] = i; } for (int i = 1; i <= m; i++) { cin >> a >> b; unite(a,b); } for (int i = 1; i <= n; i++) { if (find(where[i]) == find(i)) { anser++; } } cout << anser << endl; return 0; }
C
有2N个球 一半是白的 一半是黑的 每个白球和黑球上都有一个数字 分别都可以组成1-N
在一次操作内你可以交换相邻的两个球 问你最少需要多少次操作使得从左到右 白球和黑球各自都是递增序
解:
dp[i][j]表示现在在(i+j)的位置有1-i白球且1-j黑球正确排序所需要的最少操作数
pre[kind][i][j]表示第kind种的球在第i个位置及之前标号不小于j的有几个
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/*Huyyt*/ #include<bits/stdc++.h> #define mem(a,b) memset(a,b,sizeof(a)) #define pb push_back using namespace std; typedef long long ll; typedef unsigned long long ull; const ll LLmaxn = 2e18; const int N = 2e3 + 5; int n; int s; int dp[N][N]; int pos[2][N]; int pre[2][N * 2][N]; void init() { for (int kind = 0; kind <= 1; kind++) { for (int i = 0; i < s; i++) { for (int j = n - 1; j >= 1; j--) { pre[kind][i][j - 1] += pre[kind][i][j]; } } for (int i = 0; i < s - 1; i++) { for (int j = 0; j < n; j++) { pre[kind][i + 1][j] += pre[kind][i][j]; } } } for (int i = 0; i <= n; i++) { for (int j = 0; j <= n; j++) { dp[i][j] = INT_MAX; } } dp[0][0] = 0; } int main() { cin >> n; s = n * 2; for (int i = 0; i < s; i++) { string ch; cin >> ch; int kind = 1; int x; cin >> x; x--; if (ch[0] == 'W') { kind = 0; } pos[kind][x] = i; pre[kind][i][x]++; } init(); for (int i = 0; i <= n; i++) { for (int j = 0; j <= n; j++) { if (i < n) { int p = pos[0][i]; dp[i + 1][j] = min(dp[i + 1][j], dp[i][j] + pre[0][p][i + 1] + pre[1][p][j]); } if (j < n) { int p = pos[1][j]; dp[i][j + 1] = min(dp[i][j + 1], dp[i][j] + pre[0][p][i] + pre[1][p][j + 1]); } } } cout << dp[n][n] << endl; return 0; }