萬字長文帶你掌握Java陣列與排序,程式碼實現原理都幫你搞明白!
A - Bad Triangle
最小的兩邊和小於等於最大的邊,那麼就一定不會存在這個三角形。否則,一定存在。
#include<iostream> #include<cstring> #include<algorithm> #include<cmath> #include<cstdlib> #include<climits> #include<stack> #include<vector> #include<queue> #include<set> #include<bitset> #include<map> //#include<regex> #include<cstdio> #include <iomanip> #pragma GCC optimize(2) #define up(i,a,b) for(int i=a;i<b;i++) #define dw(i,a,b) for(int i=a;i>b;i--) #define upd(i,a,b) for(int i=a;i<=b;i++) #define dwd(i,a,b) for(int i=a;i>=b;i--) //#define local typedef long long ll; typedef unsigned long long ull; const double esp = 1e-6; const double pi = acos(-1.0); const int INF = 0x3f3f3f3f; const int inf = 1e9; using namespace std; ll read() { char ch = getchar(); ll x = 0, f = 1; while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } typedef pair<int, int> pir; #define lson l,mid,root<<1 #define rson mid+1,r,root<<1|1 #define lrt root<<1 #define rrt root<<1|1 const int N = 5e4 + 10; int T, n; int a[N]; int main() { T = read(); while (T--) { n = read(); upd(i, 1, n)a[i] = read(); if (a[1] + a[2] <= a[n]) { printf("%d %d %d\n", 1, 2, n); } else { puts("-1"); } } return 0; }
B - Substring Removal Game
看著是博弈論,實際就是統計全1段的長度和個數。然後排序後貪心的從最大的開始取即可。
#include<iostream> #include<cstring> #include<algorithm> #include<cmath> #include<cstdlib> #include<climits> #include<stack> #include<vector> #include<queue> #include<set> #include<bitset> #include<map> //#include<regex> #include<cstdio> #include <iomanip> #pragma GCC optimize(2) #define up(i,a,b) for(int i=a;i<b;i++) #define dw(i,a,b) for(int i=a;i>b;i--) #define upd(i,a,b) for(int i=a;i<=b;i++) #define dwd(i,a,b) for(int i=a;i>=b;i--) //#define local typedef long long ll; typedef unsigned long long ull; const double esp = 1e-6; const double pi = acos(-1.0); const int INF = 0x3f3f3f3f; const int inf = 1e9; using namespace std; ll read() { char ch = getchar(); ll x = 0, f = 1; while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } typedef pair<int, int> pir; #define lson l,mid,root<<1 #define rson mid+1,r,root<<1|1 #define lrt root<<1 #define rrt root<<1|1 const int N = 1e2 + 10; int T; char s[N]; int cnt[N]; int main() { T = read(); while (T--) { scanf("%s", s+1); int len = strlen(s + 1); upd(i, 0, len)cnt[i] = 0; stack<int >st; vector<int>vec; upd(i, 1, len) { if (st.empty()) { st.push(s[i]); cnt[1] = 1; } else { if (st.top() != s[i]) { st.push(s[i]); cnt[st.size()]++; } else cnt[st.size()]++; } } while (!st.empty()) { if (st.top() == '1')vec.push_back(cnt[st.size()]); st.pop(); } int ans = 0; sort(vec.begin(), vec.end()); int num = 1; for (int i = vec.size()-1; i>=0; i--,num++) { if (num & 1)ans += vec[i]; } cout << ans << endl; } return 0; }
C - Good Subarrays
連續子段的和是該子段的長度,我們就可以想到,把所有數字全部剪掉1,那麼等價於子段和是零。
問題轉化成求字首和後,找有多少個字首相等的即可。
注意單獨計算字首和是0的字首。
#include<iostream> #include<cstring> #include<algorithm> #include<cmath> #include<cstdlib> #include<climits> #include<stack> #include<vector> #include<queue> #include<set> #include<bitset> #include<map> //#include<regex> #include<cstdio> #include <iomanip> #pragma GCC optimize(2) #define up(i,a,b) for(int i=a;i<b;i++) #define dw(i,a,b) for(int i=a;i>b;i--) #define upd(i,a,b) for(int i=a;i<=b;i++) #define dwd(i,a,b) for(int i=a;i>=b;i--) //#define local typedef long long ll; typedef unsigned long long ull; const double esp = 1e-6; const double pi = acos(-1.0); const int INF = 0x3f3f3f3f; const int inf = 1e9; using namespace std; ll read() { char ch = getchar(); ll x = 0, f = 1; while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } typedef pair<int, int> pir; #define lson l,mid,root<<1 #define rson mid+1,r,root<<1|1 #define lrt root<<1 #define rrt root<<1|1 const int N = 1e5 + 10; int T, n; char a[N]; int aa[N]; ll sum[N]; map<int, ll>mp; int main() { T = read(); while (T--) { n = read(); upd(i, 0, n)aa[i] = sum[i] = 0; mp.clear(); scanf("%s", a + 1); upd(i, 1, n) aa[i] = a[i] - 1 - '0'; ll ans = 0; upd(i, 1, n){ sum[i] = sum[i - 1] + aa[i]; } upd(i, 1, n) { if (sum[i] == 0)ans++; mp[sum[i]]++; ans += mp[sum[i]] - 1; } printf("%lld\n", ans); } return 0; }
D - Colored Rectangles
可以看見的是,我們肯定會想到優先將數字更大的進行匹配,所以我們先進行排序,分別對三種顏色。那麼現在就是,從大到小的取,該怎麼取。
我們利用一個簡單的\(dp\)即可。
\(dp[i][j][k]\)表示三種顏色分別取\(i,j,k\)個的時候的最大值。
就很容易想到,進行簡單的轉移即可。
\(dp[i + 1][j][k + 1] = max(dp[i][j][k] + rr[i] * bb[k], dp[i + 1][j][k + 1]);
dp[i][j + 1][k + 1] = max(dp[i][j][k] + gg[j] * bb[k], dp[i][j + 1][k + 1]);
dp[i + 1][j + 1][k] = max(dp[i][j][k] + rr[i] * gg[j], dp[i + 1][j + 1][k]);\)
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#include <iomanip>
#pragma GCC optimize(2)
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
char ch = getchar(); ll x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
const int N = 210;
int R, G, B;
int r[N], g[N], b[N];
int dp[N][N][N];
vector<int>rr, gg, bb;
bool cmp(int a, int b) {
return a > b;
}
int ans = 0;
int main() {
R = read(), G = read(), B = read();
upd(i, 1, R)r[i] = read(), rr.push_back(r[i]);
upd(i, 1, G)g[i] = read(), gg.push_back(g[i]);
upd(i, 1, B)b[i] = read(), bb.push_back(b[i]);
rr.push_back(0); gg.push_back(0), bb.push_back(0);
sort(rr.begin(), rr.end(), cmp); sort(gg.begin(), gg.end(), cmp); sort(bb.begin(), bb.end(), cmp);
upd(i, 0, R) {
upd(j, 0, G) {
upd(k, 0, B) {
dp[i + 1][j][k + 1] = max(dp[i][j][k] + rr[i] * bb[k], dp[i + 1][j][k + 1]);
dp[i][j + 1][k + 1] = max(dp[i][j][k] + gg[j] * bb[k], dp[i][j + 1][k + 1]);
dp[i + 1][j + 1][k] = max(dp[i][j][k] + rr[i] * gg[j], dp[i + 1][j + 1][k]);
ans = max(dp[i + 1][j][k + 1], ans);
ans = max(dp[i][j + 1][k + 1], ans);
ans = max(dp[i + 1][j + 1][k], ans);
}
}
}
cout << ans << endl;
}
E - Two Types of Spells
問題的本質就是,找k個數字,乘以兩倍,其他的數字乘以一倍。(k是閃電的個數)
我們利用兩個集合進行操作。一個集合放兩倍數,一個集合放置一倍數。
當插入的時候,我們優先判斷是否能進行兩倍,即當前數字大於一倍數集合的最大值的時候。
刪除的時候直接進行集合之間的刪除。
除此之外,我們繼續維護一個k,表示當前閃電的個數,即集合-兩倍數的大小。
所以我們每一次再統計答案的時候,先判斷集合-兩倍數是否是大小是k,如果不是,新增或者刪除,從集合-一倍數中。
另外需要排除一種特殊情況,即集合-兩倍數中,全是閃電,那麼這個時候集合兩倍數就需要將最小的閃電,和最大的火進行互換(如果可以的話,否則相當於從兩倍數-集合中刪除該數字)。
可以方便進行,我們直接維護所有數字的和-ans,然後再ans+=sum[兩倍數集合]
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#include <iomanip>
#pragma GCC optimize(2)
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
char ch = getchar(); ll x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
const int N = 2e5 + 10;
int n;
set<int >s1, s2, F;
int main() {
n = read();
int cnt_l = 0;
int tp, d;
ll ans = 0;
upd(i, 1, n) {
tp = read(), d = read();
ans += d;
if (d > 0) {
if (tp == 0) {
F.insert(d);
if (s2.size() && *s2.begin() <= d)s2.insert(d), ans += d;
else s1.insert(d);
}
else {
cnt_l++;
if (s2.size() && *s2.begin() <= d)s2.insert(d), ans += d;
else s1.insert(d);
}
}
else {
if (tp == 0) {
F.erase(-d);
if (s1.count(-d))s1.erase(-d);
else s2.erase(-d),ans += d;
}
else {
cnt_l--;
if (s1.count(-d))s1.erase(-d);
else s2.erase(-d), ans += d;
}
}
while (s2.size() > cnt_l) {
ans -= *s2.begin();
s1.insert(*s2.begin());
s2.erase(s2.begin());
}
while (s2.size() < cnt_l) {
ans += *s1.rbegin();
s2.insert(*s1.rbegin());
s1.erase(--s1.end());
}
int x = 0;
if (s2.size()) {
if (F.size())x = min(x, *F.rbegin() - *s2.begin());
else x = -*s2.begin();
}
printf("%lld\n", ans + x);
}
return 0;
}
F - Controversial Rounds
題目的本質就是,給出一個長度len,判斷最多有少個,不重疊的,長度是len的全\(0\),或者全\(1\)字串。
我們進一步思考可以發現一個貪心的策略。當0,1串重疊的時候,當且僅當出現'?'的時候,我們如果將‘?’歸入當前前面的數字中,情況不會變差,所以基於該貪心,我們可以:
維護一個字尾長度,\(nxt[0][pos],nxt[1][pos]\),以\(pos\)結尾的,全\(0\),全\(1\)串的長度。繼續維護兩個vector,\(vec[0][len],vec[1][len]\)儲存,全\(0\),全\(1\)的長度是\(len\)的所有左端點。
繼而我們可以利用調和級數\(n+n/2+n/3+n/4+...+1=n*\log(n)\)進行暴力判斷。其中還有一個二分的\(log\),當每次找不到的時候,我們二分一個最小的左端點\(>=nowpos\)即可,沒有的話,直接退出。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#include <iomanip>
#pragma GCC optimize(2)
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
char ch = getchar(); ll x = 0, f = 1;
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
const int N = 1e6 + 1l;
char s[N];
int nxt[2][N];
vector<int> len[2][N];
int n;
bool check(int pos,int ter) {
if (s[pos] != '?'&&s[pos] != (ter + '0'))return 0;
else return 1;
}
int main() {
n = read();
scanf("%s", s + 1);
dwd(i, n, 1) {
if (s[i] == '1' || s[i] == '?')nxt[1][i] = 1 + nxt[1][i + 1];
if (s[i] == '0' || s[i] == '?')nxt[0][i] = 1 + nxt[0][i + 1];
}
upd(bit, 0, 1) {
for (int l = 1; l <= n;) {
if (!check(l,bit))l++;
else {
int r = l;
for (r = l; r <= n;) {
if (check(r, bit))
{
len[bit][r - l + 1].push_back(l);
r++;
}
else break;
}
l = r + 1;
}
}
}
upd(x, 1, n) {
int pos = 1;
int ans = 0;
while (pos <= n) {
if (nxt[0][pos] >= x || nxt[1][pos] >= x)pos += x, ans++;
else {
int temp1 = lower_bound(len[0][x].begin(), len[0][x].end(), pos) - len[0][x].begin();
int temp2 = lower_bound(len[1][x].begin(), len[1][x].end(), pos) - len[1][x].begin();
int pos1 = INF, pos2 = INF;
if (temp1 != len[0][x].size())pos1 = len[0][x][temp1];
if (temp2 != len[1][x].size())pos2 = len[1][x][temp2];
if (pos1 == INF && pos2 == INF)break;
pos = min(pos1, pos2);
}
}
printf("%d ", ans);
}
return 0;
}