链接:https://codeforces.com/contest/2033
A
A |
大意:
一个人跳1 5 9, 一个人跳 3 7 11,问谁能跳不超过x的最后一跳
思路:
%4, 逐个分析
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 10, INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
#define pb push_back
#define vi vector<int>
#define vii vector<pair<int, int>>
#define ff first
#define ss second
// ++ ~! */+- <<>> <> == &^| &&|| =
void solve()
{
int n;cin >> n;
n %= 4;
if (n == 0 || n == 2)cout << "Sakurako" << endl;
else cout << "Kosuke" << endl;
}
signed main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) solve();
return 0;
}
/* /\_/\
* (= ._.)
* / > \>
*/
B
B |
大意:
对主对角线操作一次,对角线上元素加一,求使得所有元素非负的最小操作数
思路:
求得主对角线元素最小值,为负就加上绝对值大小
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 10, INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
#define pb push_back
#define vi vector<int>
#define vii vector<pair<int, int>>
#define ff first
#define ss second
// ++ ~! */+- <<>> <> == &^| &&|| =
void solve()
{
int n;cin >> n;
vector<vi> g(n + 1, vi(n + 1));
map<int, int> mp;
for(int i = 1; i <= n; i ++)
for (int j = 1; j <= n; j++)
{
cin >> g[i][j];
if (g[i][j] < 0)
{
mp[i - j] = min(mp[i - j], g[i][j]);
}
}
int ans = 0;
for (int i = -n + 1; i <= n - 1; i++)ans -= mp[i];
cout << ans << endl;
}
signed main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) solve();
return 0;
}
/* /\_/\
* (= ._.)
* / > \>
*/
C
C |
大意:
一堆数,每次可以移动一个数和对称的数,及 i 和 n + 1 - i, 求最少多少相邻的数相等
思路:
两边由外到内,如果左边数跟左边相邻或者右边数跟右边相邻,交换一下(贪心,感觉这样最好,换或者不换,对外边而言一定不亏),然后记录一下,左右跟外边相邻的个数,最后奇偶讨论一下中间
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 10, INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
#define pb push_back
#define vi vector<int>
#define vii vector<pair<int, int>>
#define ff first
#define ss second
// ++ ~! */+- <<>> <> == &^| &&|| =
void solve()
{
int n;cin >> n;
vi v(n);
for (int i = 0; i < n; i++)cin >> v[i];
int cnt = 0;
for (int i = 1; i < n / 2; i++)
{
if (v[i] == v[i - 1] || v[n - i - 1] == v[n - i])swap(v[i], v[n - i - 1]);
if (v[i] == v[i - 1])cnt++;
if (v[n - i - 1] == v[n - i])cnt++;
}
if (n & 1)
{
if (v[n / 2] == v[n / 2 - 1])cnt++;
if (v[n / 2] == v[n / 2 + 1])cnt++;
}
else
{
if (v[n / 2] == v[n / 2 - 1])cnt++;
}
cout << cnt << endl;
}
signed main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) solve();
return 0;
}
/* /\_/\
* (= ._.)
* / > \>
*/
D
D |
大意:
求最大不重叠的满足区间和等于0的区间数量
思路:
从前往后读,与一个暂存量相加,用set存相加后的值,set里面默认插入一个0,然后每一次询问相加后的值是否在set里出现过,如果是就ans++,暂存量赋0,把set清空再插入个0
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 10, INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
#define pb push_back
#define vi vector<int>
#define vii vector<pair<int, int>>
#define ff first
#define ss second
// ++ ~! */+- <<>> <> == &^| &&|| =
void solve()
{
int n;cin >> n;
int sum = 0;
set<int>s;
s.insert(0);
int ans = 0;
while (n--)
{
int x;cin >> x;
sum += x;
if (s.count(sum))
{
ans++;
sum = 0;
s.clear();
s.insert(0);
}
else s.insert(sum);
}
cout << ans << endl;
}
signed main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) solve();
return 0;
}
/* /\_/\
* (= ._.)
* / > \>
*/
E
E |
大意:
对于一个排列,求最少需要多少交换操作,使得最后的排列满足p[i] = i或者p[p[i]] = i
思路:
一个排列内元素都在环中,环或大或小,p[i]=i环元素为1,p[p[i]]=i元素为2,依次类推。对于交换操作,可以用来改变环的大小,最大可以使得一个环内大小减去2。对此,我们依次遍历每一个环,求出每个环环内元素个数,然后依次求得最小删几次可以删得只剩下大小为1或2的环即可。
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 10, INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
#define pb push_back
#define vi vector<int>
#define vii vector<pair<int, int>>
#define ff first
#define ss second
// ++ ~! */+- <<>> <> == &^| &&|| =
void solve()
{
int n;
cin >> n;
vi a(n + 1);
vector<bool> vis(n + 1, false);
int num = 0;
for (int i = 1; i <= n; i++)
cin >> a[i];
int ans = 0;
for (int i = 1; i <= n; i++)
{
int num = 0;
if (vis[i]) continue;
int j = i;
while (!vis[j])
{
vis[j] = true;
num++;
j = a[j];
}
ans += (num - 1) / 2;
}
cout << ans << "\n";
return;
}
signed main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) solve();
return 0;
}
/* /\_/\
* (= ._.)
* / > \>
*/
F
F |
大意:
求第n个可以被k整除的斐波那契数
思路:
皮亚诺定理 here,斐波那契数列%k最多不超过6k个就会重复,又由一个公式
gcd(f[n],f[m]) = f[gcd(n,m)],令n = i,m=c1*i,则gcd(f[i],f[c1*i]) = f[i] ,f[k*i]) = c2*f[i] 即那么f[i]能被k整除,f[c1 * i]也能被k整除,那么第n个能被k整除的数就在n*i
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 10, INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
#define pb push_back
#define vi vector<int>
#define vii vector<pair<int, int>>
#define ff first
#define ss second
// ++ ~! */+- <<>> <> == &^| &&|| =
void solve()
{
int n, k;cin >> n >> k;
int a = 1, b = 1;
n %= mod;
vi f = {0, 1, 1};
int i = 3;
while (1)
{
f[i % 3] = (f[(i - 2) % 3] + f[(i - 1) % 3]) % k;
if (!f[i % 3]) break;
i++;
}
if (k == 1)i = 1;
cout << i % mod * n % mod << endl;
}
signed main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) solve();
return 0;
}
/* /\_/\
* (= ._.)
* / > \>
*/