J题:
由于字符串可以无限往后复制,而我们只需要求最开始的长度为n的比赛结果。复制字符串达到可以使得第一个大场分出胜负即可,之后记录从某个点开始比赛的第一场结果,以及,这场结束后的下一场开始的下标。就可以在初始字符串无限循环下去,得到任意场结果。
再利用倍增,得到从某点开始,2的任意次方局后a赢得场次,以及2的任意次方局后,下场开始的下标,就可以nlogn得到结果了。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll inf = 1e18;
long long int mod = 1000000007;
const int maxN = 2e5 + 10;
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int main() {
IOS
int n,a,b;
cin>>n>>a>>b;
string t,tmp;
cin>>t;
tmp=t;
int len=(int)t.size();
while(tmp.size()<len+2*a){
tmp+=t;
}
vector<int>winner(n+1),next(n+1);
int r,l=0;
int cnt=0;
for(r=0;r<tmp.size()&&l<n;r++){
if((tmp[r]-'0')==1)
cnt++;
if(r-l+1-cnt==a) {
winner[l] = 0;
if (tmp[l] == '1') {
cnt--;
}
next[l] = (r + 1) % n;
l++;
r--;
if((tmp[r+1]-'0')==1)
cnt--;
}
if(cnt==a){
winner[l]=1;
if(tmp[l]=='1'){
cnt--;
}
next[l]=(r+1)%n;
l++;
r--;
if((tmp[r+1]-'0')==1)
cnt--;
}
}
vector<int>lg(2e5+10);
lg[1]=0;
for(int i=2;i<=2e5;i++){
lg[i]=lg[i/2]+1;
}
vector<vector<int>>f(n+1,vector<int>(30)),g(n+1,vector<int>(30));
for(int i=0;i<n;i++){
f[i][0]=(winner[i]==1);
g[i][0]=next[i];
}
for(int j=1;j<30;j++){
for(int i=0;i<n;i++){
f[i][j]=f[i][j-1]+f[g[i][j-1]][j-1];
g[i][j]=g[g[i][j-1]][j-1];
}
}
vector<int>ans(n+1);
for(int i=0;i<n;i++){
int exp=lg[b];
int cur=(int)pow(2,exp);
int now=0;
int pos=i;
while(cur<=2*b-1){
now+=f[pos][exp];
if(now>=b){
ans[i]=1;
break;
}
if(cur-now>=b){
ans[i]=0;
break;
}
pos=g[pos][exp];
exp=lg[2*b-1-cur];
cur+=(int)pow(2,exp);
}
}
for(int i=0;i<n;i++){
cout<<ans[i];
}
cout<<endl;
return 0;
}
A题:
每个人需要先过河到对岸,减少一点体力。之后如果他的体力大于等于2,就可以划船一个来回,接R-L个人过来,被接过来的人和最开始去河对岸的人都一样,都是去掉了一点体力,之后看能不能进行来回。所以我们计算所有人过去需要的来回次数total,每个体力减少1,再除以二,并和总的需要的来回次数取最小值,得到其能走的来回次数ai。每次需要L个人来回,即L*total,ai总和大于等于L*total即可以成功。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int infmin = 0xc0c0c0c0;
const int infmax = 0x3f3f3f3f;
const int maxn = 5e5 + 10;
int h[maxn];
ll tranRound[maxn]; // 每个人的有效运输次数
signed main() {
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n, L, R;
cin >> n >> L >> R;
int reuseableCnt = 0; // 耐力值大于2的步行者数量
for (int i = 1; i <= n; i++) {
cin >> h[i];
if (h[i] > 2) {
reuseableCnt++;
tranRound[i] = (h[i] - 1) / 2;
}
}
// 一遍过
if (n <= R) {
cout << "Yes";
return 0;
}
// 不能一遍过的情况下,没有足够的人回来继续接人
if (reuseableCnt < L) {
cout << "No";
return 0;
}
ll wholeTrans = (n - R - 1) / (R - L) + 1; // 需要的完整运输次数 (-1是为了上取整)
ll wholeNum = wholeTrans * L; // 需要的总操作人数
for (int i = 1; i <= n; i++) {
if (h[i] > 2) {
wholeNum -= min(tranRound[i], wholeTrans);
}
}
if (wholeNum <= 0)
cout << "Yes";
else
cout << "No";
return 0;
}
D题
将两个数都相等的牌放在优先队列里,使他们交替排放,优先选数量多的牌。剩下的两个数不等的骨牌它们之间是一定可以排在一起的。如果优先队列里最后剩下一种牌没有排完,则需要选择那些两个元素都与这种牌不等的牌和它排在一起。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll inf = 1e18;
long long int mod = 1000000007;
const int maxN = 2e5 + 10;
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
struct Node {
int x, y;
int cnt;
bool operator<(const Node rhs) const {
return cnt < rhs.cnt;
}
} node;
int main() {
IOS
int n;
// freopen("../data/D-Dominoes!/26.in", "r", stdin);
// freopen("output.txt", "w", stdout); // 重定向输出到 output.txt
cin >> n;
priority_queue<Node> q;
map<pair<int, int>, int> tab;
for (int i = 1; i <= n; i++) {
int x, y;
cin >> x >> y;
tab[{x, y}]++;
}
for (auto &i: tab) {
int x = i.first.first;
int y = i.first.second;
if (x == y) {
node.cnt = i.second;
node.x = x, node.y = y;
q.push(node);
i.second = 0;
}
}
vector<pair<int, int>> ans;
while (!q.empty() && q.size() != 1) {
int x = q.top().x;
int y = q.top().y;
int cnt = q.top().cnt;
if (!ans.empty() && (ans.back().first == x)) {
node = {x, y, cnt};
q.pop();
int tmp = q.top().x;
int tmp_cnt = q.top().cnt;
ans.push_back({tmp, tmp});
q.pop();
tmp_cnt--;
if (tmp_cnt >= 1) {
q.push({tmp, tmp, tmp_cnt});
}
q.push(node);
}
ans.push_back({x, y});
q.pop();
cnt--;
if (cnt >= 1) {
node.cnt = cnt, node.x = x, node.y = y;
q.push(node);
}
}
int x = 0, y = 0;
int cnt = 0;
if (!q.empty()) {
cnt = q.top().cnt;
x = q.top().x;
y = q.top().y;
ans.push_back({x, y});
cnt--;
for (auto &i: tab) {
if (i.first.first != x && i.first.second != x) {
if (cnt < i.second) {
for (int j = 0; j < cnt; j++) {
ans.push_back({i.first.first, i.first.second});
ans.push_back({x, x});
}
i.second -= cnt;
cnt = 0;
break;
} else {
for (int j = 0; j < i.second; j++) {
ans.push_back({i.first.first, i.first.second});
ans.push_back({x, x});
}
cnt -= i.second;
i.second = 0;
}
}
if (cnt == 0) {
break;
}
}
}
if (cnt == 0) {
for (auto &i: tab) {
if (i.second == 0)
continue;
if (i.first.first != x) {
ans.push_back({i.first.first, i.first.second});
i.second--;
break;
}
if (i.first.second != x) {
ans.push_back({i.first.second, i.first.first});
i.second--;
break;
}
}
cout << "YES" << endl;
for (int i = 0; i < ans.size(); i++) {
cout << ans[i].first << ' ' << ans[i].second << endl;
}
int tmp = ans.back().second;
for (auto i: tab) {
if (i.second == 0)
continue;
if (i.first.first != tmp) {
cout << i.first.first << ' ' << i.first.second << endl;
i.second--;
for(int j=0;j<i.second;j++){
cout << i.first.first << ' ' << i.first.second << endl;
}
tmp = i.first.second;
continue;
}
if (i.first.second != tmp) {
cout << i.first.second << ' ' << i.first.first << endl;
i.second--;
for(int j=0;j<i.second;j++){
cout << i.first.second << ' ' << i.first.first << endl;
}
tmp = i.first.first;
}
}
} else {
cout << "NO" << endl;
}
return 0;
}