选择题
原题链接
思路
若
n
n
n为奇数
→
\rightarrow
→选择一个奇数和一个偶数
→
\rightarrow
→最大奇数n-2
若
n
n
n为偶数
→
\rightarrow
→选择一个奇数和一个偶数
→
\rightarrow
→最大奇数n-1
算法标签
思维 数学
代码
#include<bits/stdc++.h>
#define int long long
#define rep(i, a, b) for(int i=a;i<b;++i)
#define Rep(i, a, b) for(int i=a;i>b;--i)
using namespace std;
const int N = 10005;
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
void put(int x) {
if(x<0) putchar('-'),x=-x;
if(x>=10) put(x/10);
putchar(x%10^48);
}
signed main(){
int n=read();
if(n%2){
put(n-2);
}
else{
put(n-1);
}
}
填空题
原题链接
思路
遍历数组元素 → \rightarrow →若数组元素为零 → \rightarrow →按最小方法构造该元素, 即其值为前一个元素+1(该元素具有前一个元素) → \rightarrow →构造结束判断是否符合要求
算法标签
思维 构造
代码
#include<bits/stdc++.h>
#define int long long
#define rep(i, a, b) for(int i=a;i<b;++i)
#define Rep(i, a, b) for(int i=a;i>b;--i)
using namespace std;
const int N = 100005;
int a[N];
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
void put(int x) {
if(x<0) putchar('-'),x=-x;
if(x>=10) put(x/10);
putchar(x%10^48);
}
signed main(){
int n=read();
int sum=0;
bool flag=false;
rep(i, 0, n){
a[i]=read();
if(a[i])sum+=a[i];
if(!(a[i])){
if(i-1>=0)
a[i]=a[i-1]+1, sum+=a[i];
else
a[i]=1, sum+=a[i];
}
}
rep(i, 1, n){
if(a[i]<=a[i-1]){
flag=true;
}
}
if(flag){
put(-1);
}
else{
put(sum);
}
}
零一题
原题链接
思路
判断可构造条件 → \rightarrow →具有剩余0与剩余1 → \rightarrow →剩余0与剩余1个数为偶数 → \rightarrow →依次输出根据剩余0个数,剩余1个数,01串个数
算法标签
思维 构造
代码
#include<bits/stdc++.h>
#define int long long
#define rep(i, a, b) for(int i=a;i<b;++i)
#define Rep(i, a, b) for(int i=a;i>b;--i)
using namespace std;
const int N = 100005;
int a[N];
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
void put(int x) {
if(x<0) putchar('-'),x=-x;
if(x>=10) put(x/10);
putchar(x%10^48);
}
signed main(){
int a=read(), b=read(), x=read();
bool flag=false;
if(!(x%2)){
int aa=a-x/2;
int bb=b-x/2;
if(!(aa%2)&&!(bb%2)&&aa>=0&&bb>=0){
if(aa){
rep(i, 0, aa){
put(0);
}
}
if(bb){
rep(i, 0, bb){
put(1);
}
}
rep(i, 0, x/2){
put(0);
put(1);
}
}
else{
put(-1);
}
}
}
操作题
原题链接
思路
n
n
n对
x
x
x取余之后所得值即需要加上的值,假若当
b
b
b乘以
x
x
x,就无法得到所加值。
随后将
b
b
b的值乘以
x
x
x后,补充
n
n
n对
x
x
x 取余的值,同理一直补充到n。
算法标签
思维
代码
#include<bits/stdc++.h>
#define int long long
#define x first
#define y second
#define rep(i, a, b) for(int i=a;i<b;++i)
#define Rep(i, a, b) for(int i=a;i>b;--i)
using namespace std;
const int N = 100005;
int a[N];
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
void put(int x) {
if(x<0) putchar('-'),x=-x;
if(x>=10) put(x/10);
putchar(x%10^48);
}
signed main(){
int t=read();
while(t--){
int n=read(), xx=read();
vector<pair<int, int>> ans;
while(n){
int yy=n%xx;
rep(i, 0, yy){
ans.emplace_back(1, 'a');
}
n/=xx;
if(n){
ans.emplace_back(2, 'b');
}
}
put(ans.size());
puts("");
for(auto i:ans){
printf("%lld %c\n", i.x, i.y);
}
}
return 0;
}
语法题
原题链接
思路
只有当a单调上升才会有意义,若
a
i
a_i
ai
比之前小,那么本次
a
i
a_i
ai 就不需要计算。
其次我们需要能够快速求出
x
/
b
i
x/ b_i
x/bi等于
n
n
n的
x
x
x的取值范围,其取值范围为
[
b
i
∗
n
,
b
i
∗
(
n
+
1
)
−
1
]
[b_i*n,b_i*(n+1)-1]
[bi∗n,bi∗(n+1)−1]。该取值范围与条件语句区间相交处即为所有符合情况的解,计算之后即可得到答案。
对于我们的条件语句,显然他的有效范围为
[
m
a
x
a
1
.
.
.
a
i
−
1
]
[max {a_1...a_{i-1}}]
[maxa1...ai−1]。最后特判,如果原
n
n
n并没有进入一个条件语句,那么他也是合法的。此时只有一个答案。
另外,由于long long int 类型的值的大小不能超过1e18数量级,但是这里乘法可能会导致超过,但是其实可以发现,如果一个数能够进入条件语句,那么他一定小于1e9,1e9除以一个正整数是一定不会得到一个1e9以上的结果的,所以如果n大于1e9,我们可以直接return。
算法标签
数学 思维
代码
#include<bits/stdc++.h>
#define int long long
#define x first
#define y second
#define rep(i, a, b) for(int i=a;i<b;++i)
#define Rep(i, a, b) for(int i=a;i>b;--i)
using namespace std;
const int N = 100005;
int a[N], b[N];
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
void put(int x) {
if(x<0) putchar('-'),x=-x;
if(x>=10) put(x/10);
putchar(x%10^48);
}
signed main(){
int n=read();
rep(i, 1, n+1){
a[i]=read(),b[i]=read();
assert(a[i]>=1&&a[i]<=1e9), assert(b[i]>=1&&b[i]<=1e9);
}
int x=read(), ans=0, last=1;
assert(x>=0&&x<=1e18);
rep(i, 1, n+1){
last=max(last, a[i]);
}
if(x>=last){
ans++;
}
last=1;
if(x>1e9){
printf("%lld", ans);
}
rep(i, 1, n+1){
int l=x*b[i], r=x*b[i]+b[i]-1;
l=max(l, last);
r=min(r, a[i]-1);
last=max(a[i], last);
if(l>r){
continue;
}
ans+=(r-l+1);
}
printf("%lld\n", ans);
return 0;
}
平均题
原题链接
思路
首先将区间长度相同进行合并。
例如:当长度为1的时候,所有长度为1的区间的和之和等于整个区间的和。
当长度为2的时间,所有长度为2的区间的和之和等于
∑
i
=
1
n
−
1
a
i
+
a
i
+
1
\sum_{i=1}^{n-1}{a_i+a_{i+1}}
∑i=1n−1ai+ai+1
我们可以发现,这个式子还可以等于
∑
i
=
1
n
−
1
a
i
+
∑
i
=
2
n
a
i
=
∑
i
=
1
n
a
i
+
∑
i
=
2
n
−
1
a
i
\sum_{i=1}^{n-1}{a_i}+\sum_{i=2}^{n}{a_i}=\sum_{i=1}^{n}{a_i}+\sum_{i=2}^{n-1}{a_i}
∑i=1n−1ai+∑i=2nai=∑i=1nai+∑i=2n−1ai
当长度增加之后,我们可以发现长度为
i
i
i的区间的和等于长度为
i
−
1
i-1
i−1的区间的和加上
∑
j
=
i
j
=
n
−
i
+
1
a
i
\sum_{j=i}^{j=n-i+1}{a_i}
∑j=ij=n−i+1ai
当
i
>
n
/
2
i>n/2
i>n/2之后,他的值又等于
s
n
−
i
+
1
s_{n-i+1}
sn−i+1
,所以我们把之前计算的储存一下即可。
算法标签
数学 思维
代码
#include<bits/stdc++.h>
#define int long long
#define x first
#define y second
#define rep(i, a, b) for(int i=a;i<b;++i)
#define Rep(i, a, b) for(int i=a;i>b;--i)
using namespace std;
const int N = 100005;
const int mod = 1000000007;
int a[N];
int pre[N];
int sum=0, ans;
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
void put(int x) {
if(x<0) putchar('-'),x=-x;
if(x>=10) put(x/10);
putchar(x%10^48);
}
inline int pw(int a,int b){
int res=1;
while(b){
if(b&1)
res=res*a%mod;
b>>=1;
a=a*a%mod;
}
return res;
}
signed main(){
int n=read();
rep(i, 1, n+1){
a[i]=read();
pre[i]=(pre[i-1]+a[i])%mod;
}
rep(i, 1, n+1){
int l=i, r=n+1-i;
if(l<=r){
sum=(sum+(pre[r]-pre[l-1]+mod)%mod)%mod;
}
else{
sum=(sum-(pre[l-1]-pre[r]+mod)%mod+mod)%mod;
}
ans=(ans+sum*pw(i, mod-2)%mod)%mod;
}
printf("%lld", ans);
return 0;
}
计算题
原题链接
思路
对于本题,首先你需要能够快速的计算出一个带单次不匹配的回文串,有两种方法。
方法一:
在同一hash规则下,从先往后hash和从后往前hash的值相等即可保证该串是回文,如果不相等,可以将该字符串切分成两段,如果存在一段相等一段不等,那么继续判断不等的那一串,如果都不相等,那么他一定会存在两个不相等的地方。
方法二:
通过二分将第前缀相等的地方计算出来,然后跳过不等的字符,继续判断剩下的字符串是否相等。
当你知道上述方法之后答案基本上就计算出来了。
然后分类讨论一下,如果一个串是回文串,且他是一个偶数长度串,那么他无法随意改变,字符串本质不变,贡献1。
如果是回文串,并且他是一个奇数回文串,那么我们可以更改中间的字符,贡献2.
如果一个串是一个只有一个位置不等的伪回文串,那么我们可以修改不等的地方,左右两遍都可以修改成对方的样子,贡献2。
算法标签
思维 数学 哈希
代码
#include<bits/stdc++.h>
using namespace std;
const int base=2333;
unsigned long long ans,bs[2000001],h[2000001];
int m,n;
char s[2000001];
inline unsigned long long get_hsh(int l,int r)
{
return h[r]-h[l-1]*bs[r-l+1];
}
inline int query(int x,int y)
{
int ret=0,l=1,r=min(x,n-y+1);
while(l<=r)
{
int mid=l+r>>1;
if(get_hsh(n*2-x+1,n*2-x+1+mid-1)==get_hsh(y,y+mid-1))
ret=mid,l=mid+1;
else
r=mid-1;
}
return ret;
}
int main()
{
scanf("%d%s",&n,s+1);
for(int i=1;i<=n;++i)s[n*2-i+1]=s[i];
m=n<<1;
bs[0]=1;
for(int i=1;i<=m;++i)
bs[i]=bs[i-1]*base,h[i]=h[i-1]*base+s[i];
for(int i=1;i<=n;++i)
{
if(i&1)
{
int mid=i+1>>1;
int len1=query(mid,mid);
if(len1==mid)
ans+=26;
else
{
int len2=query(mid-len1-1,mid+len1+1);
if(len1+1+len2==mid)
ans+=2;
}
}
else
{
int mid1=i>>1,mid2=i+2>>1;
int len1=query(mid1,mid2);
if(len1==mid1)
++ans;
else
{
int len2=query(mid1-len1-1,mid2+len1+1);
if(len1+1+len2==mid1)
ans+=2;
}
}
}
printf("%lld",ans);
}
战绩
战果
原创不易
转载请标明出处
如果对你有所帮助 别忘啦点赞支持哈