目录
A 选择题
思路:略
代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 2e5 + 10;
int T;
void solve()
{
int n;
scanf("%d", &n);
if(n%2) cout << n-2 << endl;
else cout << n-1 << endl;
}
int main()
{
solve();
return 0;
}
B 填空题
思路:特判 a[0] ,然后判断其他的 i ,若为a[i] 不等于 0 ,则判断与前一个数的关系;若等于 0 ,则令其等于 前一个数 + 1;
代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 2e5 + 10;
int T;
void solve()
{
int n;
scanf("%d", &n);
LL sum = 0;
int a[N], x;
for(int i = 0; i < n; i ++ )
scanf("%d", &a[i]);
if( a[0] == 0 )
a[0] = 1;
for(int i = 0; i < n; i ++ )
{
if(a[i] != 0)
{
if( i && a[i] <= a[i-1])
{
puts("-1");
return ;
}
}
else a[i] = a[i-1] + 1;
sum += a[i];
}
cout << sum << endl;
}
int main()
{
solve();
return 0;
}
C 零一题
思路:剩余的 x 个数一定由 01 交错排列,则答案不成立条件有两个,1.a 或 b 的长度不够 x/2
2. a 或 b 减去 x/2 后,剩余的长度无法消去,即剩余为奇数的长度。若都满足,正常输出即可,先输出可以消去的部分,再输出不能消去的部分
代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 2e5 + 10;
int T;
void solve()
{
int a, b, x;
scanf("%d%d%d", &a, &b, &x);
LL sum = 0;
string s;
if( a < x/2 || b < x/2 )
{
puts("-1");
return;
}
int ta = a - x/2;
int tb = b - x/2;
if( ta % 2 || tb % 2 )
{
puts("-1");
return;
}
int aa = 0, bb = 0;
while(s.size() < a + b - x)
{
if(aa < ta) aa ++, s += "0";
if(aa < ta) aa ++, s += "0";
if(bb < tb) bb ++, s += "1";
if(bb < tb) bb ++, s += "1";
}
while(s.size() < a + b)
{
if(aa < a) aa ++, s += "0";
if(bb < b) bb ++, s += "1";
}
cout << s << endl;
}
int main()
{
solve();
return 0;
}
D 操作题
思路:将 n 化为 x 进制,然后将 b 变为对应的基数,加到 a 上即可
代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 2e5 + 10;
int T;
void solve()
{
int n, x;
scanf("%d%d", &n, &x);
int res = 0;
int a[N], cnt = 0;
while(n)
{
int t = n%x;
a[cnt ++] = t;
res += t;
n /= x;
}
cout << res + cnt << endl;
int b = 1;
for(int i = 0; i < cnt; i ++ )
{
while( a[i] -- )
{
printf("1 a\n");
}
b *= x;
printf("2 b\n");
}
}
int main()
{
scanf("%d", &T);
while(T -- )
solve();
return 0;
}
F 平均值
思路:枚举区间长度即可,前缀和 + 算贡献(从其他大佬那学的,tql,)
更好理解的代码:
即、前缀和的前缀和,以下为每个区间长度下子序列的表示,每个方格表示本位置的元素+1
设表示对应区间长度总和的 q j [ i ]
我们先画出前缀和的前缀和是什么样子?
设 前缀和数组为 s[N],前缀的前缀和数组 p[N]
即,
求每个区间长度总和的数组 qj[i]
qj[i] = p[n] - p[i-1] - p[n-i]
qj[1] = p[n] - p[1-1] - p[n-1]
qj[2] = p[n] - p[2-1] - p[n-2]
qj[3] = p[n] - p[3-1] - p[n-3]
qj[4] = p[n] - p[4-1] - p[n-4]
qj[5] = p[n] - p[5-1] - p[n-5]
分别画图表示为:
表示为蓝色部分为 qj[1],绿色部分为第一个p[i-1] ,红色部分为 p[n-i],如下图表示
qj[1]:
qj[2]:
qj[3]:
qj[4]:
qj[5]:
与上图区间的分析完全吻合,所以该方法正确,
注:(本人较菜,不会证明此方法,只能写个例子了,若大佬知道如何证明,评论区回复一下,本人会认真学习,并将此博客补充完整)
核心代码如下:
for(int i = 1; i <= n; i ++ ) scanf("%d", &a[i]); // 原数组
for(int i = 1; i <= n; i ++ ) s[i] = s[i-1] + a[i]; // 前缀和数组
for(int i = 1; i <= n; i ++ ) p[i] = p[i-1] + s[i]; // 前缀和的前缀和数组
//计算:
int res = 0;
for(int i = 1; i <= n; i ++ )
res += p[n] - p[i-1] - p[n-i];
AC代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 2e5 + 10, mod = 1e9 + 7;
int T;
LL s[N], p[N];
int qmi(int a, int k)
{
int res = 1;
while(k)
{
if(k & 1) res = (LL)res*a % mod;
k >>= 1;
a = (LL)a*a%mod;
}
return res;
}
void solve()
{
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i ++ )
scanf("%lld", &s[i]), s[i] = (s[i-1] + s[i])%mod;
for(int i = 1; i <= n; i ++ )
p[i] = (p[i-1] + s[i]) % mod;
LL res = 0;
LL sum = 0;
for(int i = 1; i <= n; i ++ )
// 注意减去一个数 要 +mod%mod,再乘逆元
res += ((p[n] - p[i-1] + mod)%mod - p[n-i] + mod)%mod * (qmi(i, mod-2)%mod)%mod;
cout << res << endl;
}
int main()
{
solve();
return 0;
}