A. Marin and Photoshoot
题目大意
对于给定的$01$串,可以在其中添加若干个 $1$,使得任意区间内, $0$ 的个数不超过 $1$ 的个数。
解题思路
对于本题,我们只关心前后距离不超过2的两个0
:
1. 对于010
, 不合法,需要在中间再加一个1
2. 对于100
或001
不合法,需要在两个0
中加入两个1
即: 每两个0
之间,至少需要两个1
Code
void solve()
{
int n; string s; vector<int> v;
cin >> n >> s;
for (int i = 0; i < n; i++)
if (s[i] == '0') v.push_back(i);
int res = 0;
for (int i = 1; i < v.size(); i++)
if (v[i] - v[i - 1] <= 2) res += 3 - (v[i] - v[i - 1]);
cout << res << endl;
}
B. Marin and Anti-coprime Permutation
解题思路
这道题当时模拟了n = 1,2,3的例子才找到规律
证明略.需要的话请看官方题解
如果n
是奇数
,则符合条件的排列数一定为0
如果n
是偶数
,我们只需在奇数位置上放偶数, 偶数位置上放奇数即可
对于偶数情况,可得出一个公式=> $res = ((n / 2)!)^2$
Code
void solve()
{
int n; cin >> n;
if (n & 1)
{
puts("0");
return;
}
else
{
int m = n / 2, sum = 1;
for (int i = m; i >= 1; i--) sum = (sum * i) % mod; // 求 n/2 的阶乘
int now = (sum * sum) % mod; // 求阶乘的平方
cout << now << endl;
}
}
C. Shinju and the Lost Permutation (思维)
解题思路
建议看官方题解(其实是懒得描述)
这里只提供一个关键性质:
对于全排列中 $n$ 移动后答案为1
的情况只有$[n,.....]$
所以对于给定的数组,其中只能出现一个1
,否则就不合法
Code
void solve()
{
int n; cin >> n;
for (int i = 1; i <= n; i++) cin >> c[i];
if (count(c + 1, c + 1 + n, 1) != 1) // 只能出现一个1
{
puts("NO");
return;
}
vector<int> t, a;
for (int i = 1; i <= n; i++) // 把给定的数组变为从1开头,对应于排列【n,...]的情况
{
if (c[i] != 1) t.push_back(c[i]);
else
{
for (int j = i; j <= n; j++) a.push_back(c[j]);
for (auto x : t) a.push_back(x);
}
}
for (int i = 1; i < a.size(); i++)
if (a[i] - a[i - 1] > 1)
{
puts("NO");
return;
}
puts("YES");
}
D1. 388535 (Easy Version) (位运算/规律)
题目大意
对于给定的数组 $a$ ,你需要找到一个数 $x$ ,满足 $b_i = a_i \oplus x$后,对 $b$ 排序后的结果为 $[0,1,2,3,4,5…n]$ 。问 $x$ 是多少。
解题思路
我们首先可以列出0~7的二进制
分别为
000 0 我们对于每一位进行查看(垂直): 对于第0位: 对于第1位
001 1 1 0
010 2 0 0
011 3 1 1
100 4 0 1
101 5 1 0
110 6 0 1
111 7 1 1
可以发现性质: 任意一位的前缀中,$0$ 的个数一定大于等于 $1$ 的个数。
只有满足这个性质才可以构成$b$数组排序后形成$[0,1,2,3,4,5…n]$这样的连续排列。
所以对于给定的异或后的结果,我们只需要对它的每一位0,1个数进行统计,
如果某一位的1个数大于0个数,就对这一位$\oplus$1, 因为1 $\oplus$ 1 = 0;
其实可以反向理解一波,为什么要在这一位上异或一个1? 因为正是因为x这个数上有这个0/1才使得数组$a$不符合上述性质
Code
void solve()
{
memset(cnt, 0,sizeof cnt);
int l, r; cin >> l >> r;
for (int i = l; i <= r; i++)
{
int x; cin >> x;
for (int j = 0; j < 30; j++)
cnt[j][x >> j & 1]++; // 统计每一个数的每一位的0/1个数
}
int res = 0;
for (int i = 0; i < 30; i++)
if (cnt[i][1] > cnt[i][0]) res += 1 << i;
cout << res << endl;
}
TIPS:
如果WA了,那一定是精度问题,本人代码头文件不同
大佬比赛中就想到D了嘛
不是大佬,D是补的,有一说一,这题真的很巧妙
啊,的确。我都看傻了看题解的时候 QAQ