将牌的存放分为x==y和x!=y两堆,从左到右依次放置x==y和x!=y的牌堆
对于x==y 的牌(总数记为sum),找到出现次数最多的k,讨论k的存放位置
对于x!=y的牌,容易实现相邻两个牌上的数字不同,即对于每个牌上的数字(x,y)(令x<y),以x为第一关键字进行升序,再以y为第二关键字进行升序,排序完后交换每张牌中x,y的位置(若输入中存在x==y的牌,则需将含有k的x!=y的牌放置至牌堆的最前面,以保证两个牌堆相连处不会出现相邻两个牌上数字相同的情况)
若sum>2*k,必然存在一种方式,使得相邻两个牌上的数字不同。按照剩余牌数从高到低依次向左侧放置,且需保证相邻两张上的数字不同
若(sum+1)/2==k,在两张数字为k的牌中插入一张其他数字的牌即可
若2*k>sum,参照上一种放置方式,并将剩余的牌插入到x!=y的牌堆中,且保证相邻两个牌上的数字不同,若无法实现,输出NO
code
int maxsame = 0;
bool cmp(pii a, pii b) {
if (a.first == maxsame || a.second == maxsame) {
if (b.first != maxsame && b.second != maxsame)
return 1;
else
return a.first + a.second - maxsame < b.first + b.second - maxsame;
}
if (b.first == maxsame || b.second == maxsame){
if (a.first != maxsame && a.second != maxsame)
return 0;
else
return a.first + a.second - maxsame < b.first + b.second - maxsame;
}
if (a.first == b.first)
return a.second < b.second;
return a.first < b.first;
}
void solve() {
int n;
cin >> n;
int samesum = 0;
vector<pii> pa,ans;
map<int, int>mp;
for (int i = 0; i < n; i++) {
int x, y;
cin >> x >> y;
if (x > y)
swap(x, y);
if (x == y) {
mp[x]++;
samesum++;
if (mp[x] > mp[maxsame])
maxsame = x;
}
else
pa.push_back({ x,y });
}
sort(pa.begin(), pa.end(),cmp);
if (mp[maxsame] == (samesum+1) / 2) {
for (auto u : mp) {
if (u.first == maxsame)
continue;
for (int i = 0; i < u.second; i++) {
ans.push_back({ maxsame,maxsame });
ans.push_back({ u.first,u.first });
}
}
if (samesum % 2)
ans.push_back({ maxsame,maxsame });
else
reverse(ans.begin(),ans.end());
for (auto u : pa){
if (u.second == maxsame)
ans.push_back({ u.first,u.second });
else
ans.push_back({ u.second,u.first });
}
}
else if (mp[maxsame] * 2 > samesum) {
for (auto u : mp) {
if (u.first == maxsame)
continue;
for (int i = 0; i < u.second; i++) {
ans.push_back({ maxsame,maxsame });
ans.push_back({ u.first,u.first });
mp[maxsame]--;
}
}
ans.push_back({ maxsame,maxsame });
mp[maxsame]--;
for (auto u : pa) {
if (u.second == maxsame)
ans.push_back({ u.first,u.second });
else
ans.push_back({ u.second,u.first });
if (mp[maxsame]&&u.first != maxsame && u.second != maxsame){
ans.push_back({ maxsame,maxsame });
mp[maxsame]--;
}
}
if (mp[maxsame]) {
cout << "NO\n";
return;
}
}
else {
ans.push_back({ maxsame,maxsame });
mp[maxsame]--;
priority_queue<pii> q;
for (auto u : mp){
if (u.second != 0)
q.push({ u.second,u.first });
}
int pre = maxsame;
while (!q.empty()) {
pii u = q.top();
q.pop();
if (u.second == pre) {
pii uu = q.top();
q.pop();
q.push({ u.first,u.second });
ans.push_back({ uu.second,uu.second });
if(uu.first!=1)
q.push({ uu.first - 1,uu.second });
pre = uu.second;
}
else {
ans.push_back({ u.second,u.second });
pre = u.second;
if(u.first!=1)
q.push({ u.first - 1,u.second });
}
}
reverse(ans.begin(), ans.end());
for (auto u : pa) {
if (u.second == maxsame)
ans.push_back({ u.first,u.second });
else
ans.push_back({ u.second,u.first });
}
}
cout << "YES\n";
for (auto u : ans)
cout << u.first << ' ' << u.second << '\n';
}
每一个字符代表一小局的胜负情况,每赢a个小局代表赢一个大局,赢b个大局代表最终的胜利
遍历字符串s,记录从每个字符开始赢一个大局的结束位置
倍增记录从每个开始赢2^k(0<=k<20)个大局的结束位置
最后对b按二进制位进行拆分,记录从每个位置开始赢2*b-1个大局后,两位玩家分别获胜的次数
code
int stp[100010][20];
int ans[100010][20];
void solve() {
int n, a, b;
cin >> n >> a >> b;
int i = 0, j = 0;
string s;
cin >> s;
int l = 0, r = 0, x = 0, y = 0;
while (l < n) {
if (x == a || y == a) {
stp[l][0] = r;
ans[l][0] = (x == a ? 1 : 0);
s[l] == '1' ? x-- : y--;
l++;
continue;
}
s[r] == '1' ? x++ : y++;
r = (r + 1) % n;
}
for (j = 1; j < 20; j++) {
for (i = 0; i < n; i++)
stp[i][j] = stp[stp[i][j - 1]][j - 1];
}
for (j = 1; j < 20; j++) {
for (i = 0; i < n; i++)
ans[i][j] = ans[i][j - 1] + ans[stp[i][j - 1]][j - 1];
}
for (i = 0; i < n; i++) {
int tmp = 0, loc = i;
for (j = 0; j < 20; j++) {
if (((2 * b - 1) >> j) & 1) {
tmp += ans[loc][j];
loc = stp[loc][j];
}
}
tmp >= b ? cout << '1' : cout << '0';
tmp = 0;
}
cout << "\n";
}