【luogu AT5159】RGB Balls(貪心)
阿新 • • 發佈:2021-10-27
給你一個 3*n 的字串,分別有 n 個 R,G,B 字元。
然後你可以把一個 R,G,B 組成一組,費用是它們的最長距離差。
然後你要把字串弄成 n 組,每個字元都被選到過,然後要他們的費用和最小。
問你有多少種弄的方案滿足費用和最小。
RGB Balls
題目連結:luogu AT5159
題目大意
給你一個 3*n 的字串,分別有 n 個 R,G,B 字元。
然後你可以把一個 R,G,B 組成一組,費用是它們的最長距離差。
然後你要把字串弄成 n 組,每個字元都被選到過,然後要他們的費用和最小。
問你有多少種弄的方案滿足費用和最小。
思路
我們首先考慮怎樣會有最小費用和。
那把最前和最後的貢獻分開,就是要前面的晚出現,後面的早出現。
那我們就能放到前面就放,這樣是最優的。
那接著考慮統計方案。
發現如果你要作為第三個,前面的兩個的出現順序並不重要。
那我們直接記錄六種狀態的當前個數(\(R,G,B,RG,RB,GB\))
那然後就能轉就轉,能三個就三個,每次答案乘可以轉過來的個數就可以了。
程式碼
#include<cstdio> #include<iostream> #include<algorithm> #define ll long long #define mo 998244353 using namespace std; int n; char s[300001]; ll ans, nm[6];//R G B RG RB GB int ck(int i) { if (s[i] == 'R') return 0; if (s[i] == 'G') return 1; return 2; } int to(int x, int y) { if (x > y) swap(x, y); if (x == 0 && y == 1) return 3; if (x == 0 && y == 2) return 4; return 5; } void cg(int x, int y) { if (nm[x]) nm[x]--, nm[y]++; } int main() { scanf("%d", &n); scanf("%s", s + 1); ans = 1; for (int i = 1; i <= n; i++) ans = ans * i % mo; for (int i = 1; i <= 3 * n; i++) { int now = ck(i); if (nm[5 - now]) ans = ans * nm[5 - now] % mo, nm[5 - now]--; else if (nm[(now + 1) % 3] || nm[(now + 2) % 3]) ans = ans * (nm[(now + 1) % 3] + nm[(now + 2) % 3]) % mo, cg((now + 1) % 3, to(now, (now + 1) % 3)), cg((now + 2) % 3, to(now, (now + 2) % 3)); else nm[now]++; } printf("%lld", ans); return 0; }