965div2补题
A. Find K Distinct Points with Fixed Center
思路
简单构造 ,我居然在这个题上因为没看懂英文还有机翻英太过逆天导致我WA了好几发......
AC code:
#include<bits/stdc++.h>
#define int long long
using namespace std;
void solve()
{
int x ,y,k;
cin>>x>>y>>k;
int sum=0;
for(int i=1;i<k ;i++)
{
cout<<k+i<<' '<<k+i<<'\n';
}
cout<<(k*x-(k-1)*(3*k)/2)<<' '<<(k*y-3*k*(k-1)/2)<<'\n';
}
signed main()
{
// std::ios::sync_with_stdio(0);
// std::cin.tie(0),cout.tie(0);
int t;
cin>>t;
while(t--)solve();
return 0;
}
B. Minimize Equal Sum Subarrays
《排列组合的艺术》
众所周知,农夫约翰喜欢排列组合,但我也喜欢!
给你一个长度为 \(n\) 的排列组合 \(^{\text{∗}}\) 。 \(p\) 长度为 \(n\) 。
请找出长度为 \(n\) 的排列组合 \(q\) ,使 \(p_i + p_{i+1} + \ldots + p_j = q_i + q_{i+1} + \ldots + q_j\) 的成对数 ( \(i, j\) ) ( \(1 \leq i \leq j \leq n\) ) 最小。
\(^{\text{∗}}\) 长度为 \(n\) 的排列是一个数组,由 \(n\) 个不同的整数组成,这些整数从 \(1\) 到 \(n\) 按任意顺序排列。例如, \([2,3,1,5,4]\) 是一个排列,但 \([1,2,2]\) 不是一个排列( \(2\) 在数组中出现了两次), \([1,3,4]\) 也不是一个排列( \(n=3\) ,但数组中有 \(4\) )。
思路
首先对于这个题目我们要清楚,因为这个排列是全排列中的一个,首先我们当然是尽可能地让每一个位置上的数字比原来的都不一样。
首先我们尝试先把原数组每一位后移一步,然后把最后一个数移至数组的首位,构成的整个数组保证每一个位置上的数都与原来的数不一样,原数组为 \([l,l+1,l+2,...,r]\) ,新数组是 \([l+1,l+2,...,r,r+1]\) , 由于 \(r+1\) 不等于 \(l\) 所以各个部分都不相同 ,且由于每个部分都交换了一个元素,所以每个部分的和都不相同
总结:先推出大概的符合题意的答案的一些性质,然后就需要发散思维猜一下答案
AC code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=2e5+9;
int p[maxn];
int b[maxn];
void solve()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)cin>>p[i];
int l=n/2,r=n;
int mid=l;
l--;
for(int i=1;i<n;i++)
{
b[i]=p[i+1];
}
b[n]=p[1];
for(int i=1;i<=n;i++)
{
cout<<b[i]<<" \n"[i==n];
}
}
signed main()
{
// std::ios::sync_with_stdio(0);
// std::cin.tie(0),cout.tie(0);
int t;
cin>>t;
while(t--)solve();
return 0;
}
C. Perform Operations to Maximize Score
我看到萨蒂亚姆343了。我在发抖这次请多出一些中值问题。我喜欢这些求求你,satyam343,我们相信你。
- satyam343最忠实的粉丝
给你一个长度为 \(n\) 的数组 \(a\) 和一个整数 \(k\) 。同时给你一个长度为 \(n\) 的二进制数组 \(b\) 。
您最多可以执行以下操作 \(k\) 次:
- 选择索引 \(i\) ( \(1 \leq i \leq n\) ),使得 \(b_i = 1\) .设为 \(a_i = a_i + 1\) (即将 \(a_i\) 增加 \(1\) )。
您的得分定义为 \(\max\limits_{i = 1}^{n} \left( a_i + \operatorname{median}(c_i) \right)\) ,其中 \(c_i\) 表示从 \(a\) 中删除 \(a_i\) 后得到的长度为 \(n-1\) 的数组。换句话说,您的得分是 \(a_i + \operatorname{median}(c_i)\) 在从 \(1\) 到 \(n\) 的所有 \(i\) 中的最大值。
请找出如果以最佳方式进行运算所能得到的最高分。
对于任意数组 \(p\) , \(\operatorname{median}(p)\) 被定义为 \(p\) 的 \(\left\lfloor \frac{|p|+1}{2} \right\rfloor\) -th 最小元素。例如, \(\operatorname{median} \left( [3,2,1,3] \right) = 2\) 和 \(\operatorname{median} \left( [6,2,4,5,1] \right) = 4\) 。
思路
这个题目首先模拟是非常麻烦的,但是这个题目让人感觉很有二分的味道
可是我比赛的时候最后十分钟才看出来,教训就是写之前先想想思路实现起来会不会很麻烦,存不存在更加简单但高效的方法不过这题就算二分答案实现起来也存在好多细节要处理,也许是我太菜了结果就是分两种情况,第一种情况就是逮到一个 \(b_i =1\) 的数使劲加,让它成为最大值并且让一部分的 \(k\) 直接加到最大值上;然后第二种情况就是最大值就是原最大值,然后我们把中间的数进行操作,最大程度地提高中位数的最大值,而处理这个情况就可以使用二分的方法,暴力枚举中位数可能的情况,并查询中位数可以满足的最大值。这里可以证明不可能出现两种策略同时使用的情况,因为如果已经有一个数可以加到大于原本的最大值了,那如果把操作中位数的次数全部加到那个数上,显然这个策略比两种策略同时用要有效,因为中位数想要加 \(1\) , 所需要的代价必须大于等于 \(1\).然后最后的答案就是比较两种策略的最大值就可以了!
AC code
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 2e5 + 9;
// int a[maxn],b[maxn];
struct num
{
int a, b;
};
int mid(int x)
{
return (x + 1) / 2;
}
num T[maxn];
int ct[maxn], x = 0;
void solve()
{
int n, k;
cin >> n >> k;
bool OK = false;
for (int i = 1; i <= n; i++)
cin >> T[i].a;
for (int i = 1; i <= n; i++)
{
cin >> T[i].b;
if (T[i].b)
{
OK = true;
}
}
sort(T + 1, T + 1 + n, [&](num &a, num &b)
{ return a.a < b.a; });
if (!OK)
{
cout << T[n].a + T[mid(n-1)].a << '\n';
return;
}
for (int i = 1; i <= n; i++)
{
if (T[i].b)
ct[++x] = i;
}
int t1 = mid(n-1);
int ans = -1;
if (k - (T[n].a - T[ct[x]].a) <= 0)
{
ans = T[n].a + T[t1].a;
}
else
{
T[ct[x]].a += k;
sort(T + 1, T + 1 + n, [&](num &a, num &b)
{ return a.a < b.a; });
ans = T[n].a + T[t1].a;
T[n].a -= k;
sort(T + 1, T + 1 + n, [&](num &a, num &b)
{ return a.a < b.a; });
}
auto check=[&](int m)
{
int cnt1=0,cnt2=0;
int sum=k;
for(int i=1;i<=n;i++)
{
if(T[i].a>=m)break;
if(T[i].b)
{
cnt2++;
}
else
{
cnt1++;
}
}
if(cnt1>=t1)return false;
if(cnt1+cnt2<t1)return true;
cnt2=0;
for(int i=1;i<=n;i++)
{
if(T[i].a>=m)break;
if(T[i].b)
{
cnt2++;
if(cnt1+cnt2>=t1)
{
sum-=m-T[i].a;
}
}
}
if(sum<0)return false;
return true;
};
int l0=T[t1].a,r0=T[n].a,mid;
int ans0=0;
while(l0<=r0)
{
mid=(l0+r0)>>1;
if(check(mid))
{
ans0=mid;
l0=mid+1;
}
else
{
r0=mid-1;
}
}
cout<<max(ans0+T[n].a,ans)<<'\n';
}
signed main()
{
// std::ios::sync_with_stdio(0);
// std::cin.tie(0),cout.tie(0);
int t;
cin >> t;
while (t--)
solve();
return 0;
}
/*
*/
D. Determine Winning Islands in Race
MOOOOOOOOOOOOOOOOO
— Bessie the Cow, The Art of Racing on Islands
Two of Farmer John's cows, Bessie and Elsie, are planning to race on \(n\) islands. There are \(n - 1\) main bridges, connecting island \(i\) to island \(i + 1\) for all \(1 \leq i \leq n - 1\). Additionally, there are \(m\) alternative bridges. Elsie can use both main and alternative bridges, while Bessie can only use main bridges. All bridges are one way and can only be used to travel from an island with a lower index to an island with a higher index.
Initially, Elsie starts on island \(1\), and Bessie starts on island \(s\). The cows alternate turns, with Bessie making the first turn. Suppose the cow is on island \(i\). During a cow's turn, if there are any bridges connecting island \(i\) to island \(j\), then the cow can move to island \(j\). Then, island \(i\) collapses, and all bridges connecting to island \(i\) also collapse. Also, note the following:
- If there are no bridges connecting island \(i\) to another island, then island \(i\) collapses, and this cow is eliminated from the race.
- If the other cow is also on island \(i\), then after this cow moves to another island, the island collapses, and the other cow is eliminated from the race.
- After an island or bridge collapses, no cows may use them.
- If a cow is eliminated, their turn is skipped for the rest of the race.
The race ends once either cow reaches island \(n\). It can be shown that regardless of the cows' strategies, at least one cow reaches island \(n\). Bessie wins if and only if she reaches island \(n\) first.
For each \(1 \leq s \leq n - 1\), determine whether Bessie wins if she starts the race on island \(s\). Assume both cows follow optimal strategies to ensure their own respective victories.
呜呜呜
- 奶牛贝西,在岛屿上竞速的艺术
约翰农场主的两头奶牛贝西和埃尔西打算在 \(n\) 个小岛上比赛。岛上有 \(n - 1\) 座主桥,连接 \(i\) 岛和 \(i + 1\) 岛,共 \(1 \leq i \leq n - 1\) 座。此外,还有 \(m\) 座备用桥梁。艾尔西可以使用主桥和备用桥,而贝西只能使用主桥。所有桥梁都是单向*的,只能用于从指数较低的岛屿前往指数较高的岛屿。
一开始,艾尔西从岛屿 \(1\) 开始,贝西从岛屿 \(s\) 开始。两头奶牛交替轮流,贝西先轮流。假设奶牛位于 \(i\) 岛上。在奶牛的回合中,如果有任何桥梁连接岛屿 \(i\) 和岛屿 \(j\) ,那么奶牛可以移动到岛屿 \(j\) 。然后,岛屿 \(i\) 坍塌,连接岛屿 \(i\) 的所有桥梁也会坍塌。另外,请注意以下几点:
- 如果没有桥梁连接岛屿 \(i\) 和另一个岛屿,那么岛屿 \(i\) 就会坍塌,这头牛就会被淘汰出局。
- 如果另一只奶牛也在岛屿 \(i\) 上,那么这只奶牛移动到另一个岛屿后,岛屿就会坍塌,另一只奶牛也会被淘汰出局。
- 岛屿或桥梁坍塌后,任何奶牛都不得使用。
- 如果一头奶牛被淘汰,那么在接下来的比赛中它的回合将被跳过。
任何一头奶牛到达岛屿 \(n\) 后,比赛结束。可以证明,无论奶牛的策略如何,至少有一头奶牛会到达 \(n\) 岛。贝西获胜的条件是且仅当它首先到达岛屿 \(n\) 。
对于每个 \(1 \leq s \leq n - 1\) ,如果贝西在 \(s\) 岛上开始比赛,它是否会赢。假设两头牛都采取了最佳策略,以确保各自获胜。
思路
每一个备用 alternate bridge 都会产生一个必败区间 ,若这个区间的起点为 \(t_1\),终点为 \(t_2\),那么如果对手可以比 Bessie 先到 \(t_2\) (且不经过Bessie 走过的区间),那么就 Bessie 必败 ,取对手 Elsie 到达 \(t_1\) 的最短时间是 \(dp[t_1]\) ,那么也就是这个必败区间就是 \([t_1+1,t_2-dp[t_1]-2] (t_1+1 \leq t_2-dp[t_1]-2)\) ,然后我们可以先用动态规划先求最短路径,然后再遍历每一个alternate bridge 利用差分构建前缀方程,最后非必败区间的点就是必胜即可得出答案!
AC code
#include <bits/stdc++.h>
#define print(x) cout << #x << '=' << x << '\n'
#define int long long
using namespace std;
const int maxn = 2e5 + 9;
vector<vector<int>> to;
void solve()
{
int n, m, u, v;
cin >> n >> m;
to.assign(n + 1, vector<int>());
pair<int, int> t[m + 1];
for (int i = 1; i <= m; i++)
{
cin >> u >> v;
to[u].push_back(v);
t[i] = pair<int, int>{u, v};
}
for (int i = 1; i < n; i++)
to[i].push_back(i + 1);
vector<int> ans(n + 1, 0), dp(n + 1, 0x7ffffff);
dp[1] = 0;
for (int i = 1; i <= n; i++)
{
for (auto a : to[i])
{
dp[a] = min(dp[i] + 1, dp[a]);
}
}
for (int _ = 1; _ <= m; _++)
{
int t1 = t[_].first;
int t2 = t[_].second;
int x1 = dp[t1];
if (t1 + 1 <= t2 - x1 - 1)
{
ans[t1 + 1]++;
ans[t2 - x1 - 1]--;
}
}
for (int i = 1; i < n; i++)
{
ans[i] += ans[i - 1];
cout << (ans[i] ? 0 : 1);
}
cout << '\n';
}
signed main()
{
std::ios::sync_with_stdio(0);
std::cin.tie(0), cout.tie(0);
int t;
cin >> t;
while (t--)
solve();
return 0;
}