感觉g是一个复杂的树上二分+dp,现在没有能力补
一场全是思维题
A Sakurako and Kosuke
思路
一个人往左边走一个奇数,一个人往右走一个奇数,很简单就可以知道,偶数是一个人,奇数也就是一人
代码
void solve() {
ll x;
cin >> x;
if (x & 1) {
cout << "Kosuke";
}
else {
cout << "Sakurako";
}
}
B-- Sakurako and Water
思路
不难发现,如果我们进行一个矩形的对角线进行操作就对最大的进行操作就可以了,对矩形的所有的对角线进行遍历,最少的操作就是最小的数
代码
void solve() {
ll n;
cin >> n;
vector<vector<ll>>arr(n + 2,vector<ll>(n + 2));
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
cin >> arr[i][j];
}
}
ll ans = 0;
for (int i = 1; i <= n; i++) {
ll j = 1;
ll minn = 0;
ll k = i;
while (k <= n && j <= n) {
minn = min(minn, arr[k][j]);
k++;
j++;
}
if (minn <= 0) {
ans = ans - minn;
}
}
for (int j = 2; j <= n; j++) {
ll i = 1;
ll k = j;
ll minn = 0;
while (i <= n && k <= n) {
minn = min(minn, arr[i][k]);
i++;
k++;
}
if (minn <= 0) {
ans = ans - minn;
}
}
cout << ans;
}
C-Sakurako's Field Trip
思路
我们从中间或者两边开始移动就可以
证明:首先对于中间的2个或者3个数,移动不一定没有区别,例如 1 2 3 4 5,234是可以不用注意的,然后到了1 5,就是看看1是挨着2还是挨着5了,不需要注意1的左边和5的右边
代码
void solve() {
ll n;
cin >> n;
vector<ll>arr(n + 2);
for (int i = 1; i <= n; i++) {
cin >> arr[i];
}
ll l = n / 2;
ll r = n / 2 + 1;
if (n & 1) {
r++;
}
l--;
r++;
while (l >= 1 && r <= n) {
if (arr[l] == arr[l + 1] && arr[r] == arr[r - 1]) {
swap(arr[l], arr[r]);
}
else {
ll x = 0;
if (arr[l] == arr[l + 1]) {
x++;
}
if (arr[r] == arr[r - 1]) {
x++;
}
ll y = 0;
if (arr[l] == arr[r - 1]) {
y++;
}
if (arr[r] == arr[l + 1]) {
y++;
}
if (y <= x) {
swap(arr[l], arr[r]);
}
}
l--;
r++;
}
ll ans = 0;
for (int i = 1; i < n; i++) {
if (arr[i] == arr[i + 1]) {
ans++;
}
}
cout << ans;
}
D-- Kousuke's Assignment
思路
队友有用dp写的,但是暴力的复杂度是明显能过的,我这边写了个暴力的,我们从前往后遍历,统计前缀和,如果遇到相等的前缀和或者当前的前缀和为0,那么就是1个答案,然后清空map往下即可,有一点可能会产生疑惑,就是有没有可能前面的需要到后面产生最优解,实际上简单手搓就知道不会
代码
void solve() {
ll n;
cin >> n;
vector<ll>arr(n + 2);
for (int i = 1; i <= n; i++) {
cin >> arr[i];
}
map<ll, ll>brr;
ll sum = 0;
ll ans = 0;
for (int i = 1; i <= n; i++) {
if (arr[i] == 0) {
ans++;
brr.clear();
sum = 0;
continue;
}
sum = sum + arr[i];
if (brr.count(sum) || sum == 0) {
sum = 0;
ans++;
brr.clear();
continue;
}
brr[sum]++;
}
cout << ans;
}
E-Sakurako, Kosuke, and the Permutation
思路
通过题意不难判断,我们仅需要满足第二点即可,因为第一点包含在第二点里面,然后会发现,我们的区间最多形成的是二元环才可以,在受挫案例+结论证明下,对于一个n个点的环,只需要进行(n-1)/2就可以降低为最小为二元环的,然后并查集维护即可 赛时数组开小差点红温
代码
ll arr[2000021];
ll find(ll x) {
if (arr[x] == x) {
return x;
}
return arr[x] = find(arr[x]);
}
void join(ll x, ll y) {
if (find(x) != find(y)) {
arr[find(x)] = find(y);
}
}
void solve() {
ll n;
cin >> n;
for (int i = 1; i <= n; i++) {
arr[i] = i;
}
vector<ll>brr(n + 2);
for (int i = 1; i <= n; i++) {
cin >> brr[i];
if (brr[i] != i) {
join(i, brr[i]);
}
}
map<ll, ll>dp;
for (int i = 1; i <= n; i++) {
ll a = find(i);
dp[a]++;
}
ll sum = 0;
for (int i = 1; i <= n; i++) {
if (dp[i] >= 3) {
sum = sum + (dp[i] - 1) / 2;
}
}
cout << sum;
}
F-- Kosuke's Sloth
思路
感觉像诈骗提,对于feibonaxie数列有一个性质,也就是第k项如果能整除以x那么第xi项均可以整除以x,那么我们找到第一项能整除k的下表然后乘以n就可以了
代码
ll dp[10002000];
void solve() {
cin >> n >> k;
if (k == 1) {
cout << n % mod;
return;
}
ll ans = 0;
dp[1] = 1;
dp[2] = 1;
for (int i = 3;; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
dp[i] = dp[i] % k;
if (dp[i] == 0) {
ans = i;
break;
}
}
n = n % mod;
ans = ans % mod;
ans = ans * n % mod;
cout << ans;
}