A. Casimir's String Solitaire
題意:給定一個只包含"A","B","C"的字符串,只能進行兩種操作,1.消除"A"和"B",2.消除"C"和"B",問在進行多次操作后,是否會變為空串
分析:統計A和C的數目是否等於B的數目
代碼:
#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>
#include <vector>
#define x first
#define y second
#define MAX(a,b,c) max(max(a, b),c)
#define MIN(a,b,c) min(min(a, b),c)
#define debug(x) cout<<#x<<":"<<x<<endl;
#define endl '\n'
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 3e5 + 10, mod = 1e9 + 7;
int n, m, t, k;
int s[N], dp[N], f[N];
char g[N];
string str;
vector<int> vec;
void solve()
{
cin >> str;
int a = 0, b = 0;
for (int i = 0; i < str.size(); i++)
if (str[i] == 'B') a++;
else b++;
if (a == b) puts("YES");
else puts("NO");
}
int main()
{
t = 1;
cin >> t;
while(t--)
solve();
return 0;
}
B. Shifting Sort
題意:給出一個數組,n個元素,只能進行1種操作,選定l,r,d,表示將l到r的區間,左移d位,最左邊左移到最右邊,總次數不超過n,每次操作d>0
分析:數據范圍小,暴力移動,每回將最小的數移動到左邊,第i輪維護好前i個數,因為移動位數不能為0,所以將答案存下來,之后輸出
代碼:
#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>
#include <vector>
#define x first
#define y second
#define MAX(a,b,c) max(max(a, b),c)
#define MIN(a,b,c) min(min(a, b),c)
#define debug(x) cout<<#x<<":"<<x<<endl;
#define endl '\n'
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 3e5 + 10, mod = 1e9 + 7;
int n, m, t, k;
int s[N], dp[N], f[N];
char g[N];
string str;
vector<int> vec;
void solve()
{
cin >> n;
vec.clear();
for (int i = 1; i <= n; i++)
cin >> s[i];
for (int i = 1; i < n; i++)
{
int k = i;
for (int j = i; j <= n; j++)
if (s[j] < s[k])
k = j;
if (k == i) continue;
vec.push_back(i);
vec.push_back(n);
vec.push_back(k-i);
for (int j = i; j <= n; j++)
f[j] = s[(j + k - i - i) % (n - i + 1) + i];
for (int j = i; j <= n; j++)
s[j] = f[j];
}
printf("%d\n", vec.size() / 3);
for (int i = 0; i < vec.size(); i++)
{
if (i && i % 3 == 0) printf("\n");
else if (i) printf(" ");
printf("%d", vec[i]);
}puts("");
}
int main()
{
t = 1;
cin >> t;
while(t--)
solve();
return 0;
}
C. Ticks
題意:給出n*m的圖,初始均為白色,小明將一部分塗成黑色,表示黑色都是長度為2d+1,左右對稱的對號,d>=k,給出n,m,k,詢問該圖是否可能是小明按其規則塗黑的
分析:對於每一個黑色點(*),當做中心點,去查左右兩邊長度是否大於等於k,如果成立,將這些點都標記下來,最后去搜是否有黑色點且枚被標記過的,有的話輸出NO,否則輸出YES
代碼:
#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>
#include <vector>
#define x first
#define y second
#define MAX(a,b,c) max(max(a, b),c)
#define MIN(a,b,c) min(min(a, b),c)
#define debug(x) cout<<#x<<":"<<x<<endl;
#define endl '\n'
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 3e2 + 10, mod = 1e9 + 7;
int n, m, t, k;
int s[N], dp[N], f[N];
char g[N][N];
int h[N][N];
string str;
vector<int> vec;
void solve()
{
cin >> n >> m >> k;
k++;
for (int i = 0; i < n; i++)
cin >> g[i];
for (int i = 0; i <= m; i++) g[n][i] = '.';
for (int i = 0; i <= n; i++) g[i][m] = '.';
// for (int i = 0; i <= n; i++)
// {
// for (int j = 0; j <= m; j++)
// printf("%c", g[i][j]);
// puts("");
// }printf("AAAA%c\n", g[3][1]);
for (int i = 0; i <= 10; i++)
for (int j = 0; j <= 20; j++)
h[i][j] = 0;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (g[i][j] == '*')
{
int a = 0, b = 0;
while (g[i - a][j - a] == '*' && g[i - a][j + a] == '*')
{
a++;
if (i < a || j < a) break;
}
if (a >= k)
{
a = 0;
while (g[i - a][j - a] == '*' && g[i - a][j + a] == '*')
{
h[i-a][j-a] = 1;
h[i-a][j+a] = 1;
a++;
if (i < a || j < a) break;
}
}
}
}
}
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (g[i][j] == '*' && h[i][j] == 0)
{
puts("NO");
return;
}
}
}
puts("YES");
}
int main()
{
t = 1;
cin >> t;
while(t--)
solve();
return 0;
}
D. Productive Meeting
題意:每個人可以操作n次,每次操作需要兩個人同時進行,最初給出每個人的操作次數,詢問如何搭配才能總操作次數最多
分析:貪心,每次選取當前最多操作次數的和當前第二多操作次數的進行操作即可,因為除此以外不可能更優,優先隊列維護即可,存放PII,答案暫存,最后輸出
代碼:
#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>
#include <vector>
#include <queue>
#define x first
#define y second
#define MAX(a,b,c) max(max(a, b),c)
#define MIN(a,b,c) min(min(a, b),c)
#define debug(x) cout<<#x<<":"<<x<<endl;
#define endl '\n'
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 3e5 + 10, mod = 1e9 + 7;
int n, m, t, k;
int s[N], dp[N], f[N];
char g[N];
string str;
vector<PII> vec;
priority_queue<PII> q;
void solve()
{
cin >> n;
vec.clear();
for (int i = 1; i <= n; i++)
{
int a;
cin >> a;
if (a) q.push({a,i});
}
while (q.size() > 1)
{
PII a = q.top();
q.pop();
PII b = q.top();
q.pop();
vec.push_back({a.y, b.y});
if (a.x > 1) q.push({a.x - 1, a.y});
if (b.x > 1) q.push({b.x - 1, b.y});
}
if (q.size()) q.pop();
cout << vec.size() << endl;
for (int i = 0; i < vec.size(); i++)
{
printf("%d %d\n", vec[i].x, vec[i].y);
}
}
int main()
{
t = 1;
cin >> t;
while(t--)
solve();
return 0;
}
E1. Permutation Minimization by Deque
題意:給出1到n,n個數的置換,每回操作只能放最前和最后,輸出這些數所能湊成的最小元素序列
分析:因為每個數都不相同,所以如果比當前第一個數小,就放前面,否則無條件放后面,模擬走一遍
代碼:
#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>
#include <vector>
#define x first
#define y second
#define MAX(a,b,c) max(max(a, b),c)
#define MIN(a,b,c) min(min(a, b),c)
#define debug(x) cout<<#x<<":"<<x<<endl;
#define endl '\n'
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 3e5 + 10, mod = 1e9 + 7;
int n, m, t, k;
int s[N], dp[N], f[N];
char g[N];
string str;
vector<int> vec, vec1;
void solve()
{
vec.clear();
vec1.clear();
cin >> n;
int a;
cin >> a;
vec.push_back(a);
for (int i = 1; i < n; i++)
{
cin >> a;
if (a < vec[vec.size() - 1]) vec.push_back(a);
else vec1.push_back(a);
}
cout << vec[vec.size() - 1];
for (int i = vec.size() - 2; i >= 0; i--)
{
printf(" %d", vec[i]);
}
for (int i = 0; i < vec1.size(); i++)
{
printf(" %d", vec1[i]);
}puts("");
}
int main()
{
t = 1;
cin >> t;
while(t--)
solve();
return 0;
}
E2. Array Optimization by Deque
題意:條件同E1,詢問答案的逆序對最小是多少
分析:分析可得,不管當前數放前面還是后面,對后續的數都沒有影響,這里的局部最優能推出全局最優,所以每回判斷放前面增加的逆序對多還是放后面逆序對增加的多,放過去就好,過程用了樹狀數組+離散化
代碼:
#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>
#include <vector>
#include <queue>
#define x first
#define y second
#define MAX(a,b,c) max(max(a, b),c)
#define MIN(a,b,c) min(min(a, b),c)
#define debug(x) cout<<#x<<":"<<x<<endl;
#define endl '\n'
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 2e5 + 10, mod = 1e9 + 7;
ll n, m, t, k;
ll s[N], dp[N], f[N];
ll tr[N];
string str;
vector<int> vec;
int lowbit(int x)
{
return x & -x;
}
void add(int x, int c)
{
for (int i = x; i < N; i += lowbit(i))
tr[i] += c;
}
ll sum(int x)
{
ll res = 0;
for (int i = x; i; i -= lowbit(i))
res += tr[i];
return res;
}
void solve()
{
vec.clear();
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> s[i];
vec.push_back(s[i]);
}
sort(vec.begin(), vec.end());
vec.erase(unique(vec.begin(), vec.end()), vec.end());
ll ans = 0;
for (int i = 1; i <= n; i++)
{
int a = lower_bound(vec.begin(), vec.end(), s[i]) - vec.begin() + 1;
add(a, 1);
ll res = sum(a - 1);
ll res1 = sum(a);
ans += min(res, i - res1);
}
cout << ans << endl;
for (int i = 1; i <= n; i++)
{
int a = lower_bound(vec.begin(), vec.end(), s[i]) - vec.begin() + 1;
add(a, -1);
}
}
int main()
{
t = 1;
cin >> t;
while(t--)
solve();
return 0;
}
F. Array Stabilization (AND version)
題意:給出n,m,d,長度為n的0,1數組,每回操作將數組所有的數向右移動d位,並與原有的數求與&,最右的最左相連,詢問多少次操作后會使得數組全0,如果不可能輸出-1
分析:考慮0的轉移,0轉移d位后是0可推出當前循環,轉移后是1,那么轉移后的操作次數必定比當前操作次數多1,循環轉移即可,每個位置便利一遍,時間復雜度O(n),做完后,查找所有位置是1的地方是否標記過步數,沒有的話意味着該點不可達,輸出-1,否則輸出所有1的點的標記的最大值
代碼:
#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_map>
#include <vector>
#include <queue>
#define x first
#define y second
#define MAX(a,b,c) max(max(a, b),c)
#define MIN(a,b,c) min(min(a, b),c)
#define debug(x) cout<<#x<<":"<<x<<endl;
#define endl '\n'
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1e6 + 10, mod = 1e9 + 7;
int n, m, t, k;
int s[N], dp[N], f[N];
unordered_map<int, int> ma;
string str;
vector<int> vec;
void solve()
{
ma.clear();
int d;
cin >> n >> d;
for (int i = 0; i < n; i++)
scanf("%d", &s[i]);
for (int i = 0; i < n; i++)
{
if (s[i] == 0)
{
int j = i;
while (s[(j + d) % n] == 1)
{
if (ma[(j + d) % n]) break;
ma[(j + d) % n] = ma[j] + 1;
j = (j + d) % n;
}
}
}
int ans = 0;
for (int i = 0; i < n; i++)
{
if (s[i] == 1)
{
if (ma[i])
{
ans = max(ans, ma[i]);
}
else
{
puts("-1");
return;
}
}
}
cout << ans << endl;
}
int main()
{
t = 1;
cin >> t;
while(t--)
solve();
return 0;
}
G. Minimal Coverage
題意:有n根棍子,數量不超過1000,長度不超過1000,按給出順序擺放棍子放到一維直線上,每次擺放,必須用根子的一端跟前一次沒相連的一段相連,另一端可以往左,可以往右,比如說前一次的末端在x,這次的木根長度為d,擺放位置可以為[x-d,x],下一次需要連在[x-d],或者擺放位置為[x,x+d],下一次需要連在[x+d],詢問n跟根子總覆蓋長度最小值
分析:二維dp,假設前n端已經維護好了,那么對於每個位置,我放下去的跟下一段相連的當前值,就相當於要么跟前一段連,要么跟后一段連,他們兩者的最小值,以及從該點找,意味着之前已經到了這個點了,也就是答案至少也是這個點,所以每回三個點去比較,前后比小值,最小不能低於自己的位置,這么做的思路,其實是因為每一根都一定連接着前面的那根根子,一路推回去,使得最開始的那根棍子位置不定了,不是題里要求的在原點,事實上最初的棍子在哪對答案並沒有任何影響,雖然最初是當做在原點做的吧,這里只是說明一下這么做的正確性,原理。
代碼:
#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>
#include <vector>
#define x first
#define y second
#define MAX(a,b,c) max(max(a, b),c)
#define MIN(a,b,c) min(min(a, b),c)
#define debug(x) cout<<#x<<":"<<x<<endl;
#define endl '\n'
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 3e5 + 10, mod = 1e9 + 7, INF = 1e9;
int n, m, t, k;
int s[N], dp[N], f[N];
char g[N];
string str;
vector<int> vec;
int a[10005];
int d[10005][2005];
void solve()
{
cin >> n;
for(int i = 1;i <= n;i++) cin >> a[i];
for(int i = 0;i <= 2000;i++) d[0][i] = i;
for(int i = 1;i <= n;i++) {
for(int j = 0;j <= 2000;j++) {
d[i][j] = INF;
if(j-a[i] >= 0) d[i][j] = min(d[i][j],max(d[i-1][j-a[i]],j));
if(j+a[i] <= 2000) d[i][j] = min(d[i][j],max(d[i-1][j+a[i]],j));
}
}
int ans = INF;
for(int i = 0;i <= 2000;i++) ans = min(ans,d[n][i]);
cout << ans << '\n';
}
int main()
{
t = 1;
cin >> t;
while(t--)
solve();
return 0;
}