B.tomorin的字符串迷茫值
解题思路:
对于mygo每两个字符之间只能相隔一个或0个字符,否则不满足条件;
对于删除方案,需要求出长度为i字符串的方案数(斐波那契数列),当满足条件后,需要将当前字符串可操作数*之前的方案,类似于排列组合问题。
代码如下:
#include <bits/stdc++.h>
#include <iostream>
#define int long long
#define endl '\n'
#define d 1000000007
using namespace std;
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int f[200005];
f[0]=1,f[1]=2;
for(int i=2;i<=200000;i++)
f[i]=(f[i-1]+f[i-2])%d; //可以删除长度为i字符串的方案数(不删除也是一种方案)
string s;
cin>>s;
int t=s.length(),sum=0;
for(int i=0;i<t;i++)
{
if(s[i]=='m')
{
for(int a=1;a<=2;a++)
for(int b=1;b<=2;b++)
for(int c=1;c<=2;c++)
if(i+a+b+c<t&&s[i+a]=='y'&&s[i+a+b]=='g'&&s[i+a+b+c]=='o')
sum=(sum+f[i]*f[t-1-i-a-b-c])%d; //当前方案数*之前方案数,类似于前缀和
}
}
cout<<sum;
return 0;
}
C.anon的私货
题目:
解题思路:
平均数 = 连续子数组的和 / (连续数组的个数+两侧0的个数)>=1
此问题可以转换为每插入一个0,0两侧的数都要-1,同时要满足两侧最小的那个数>=1.
对样例分析:
代码如下:
#include <bits/stdc++.h>
#include <iostream>
#define int long long
#define endl '\n'
using namespace std;
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n,a[100005],sum=0;
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
sum+=a[1]-1;a[1]=1; //1之前可以插入的0
for(int i=2;i<=n;i++)
{
int j=min(a[i-1],a[i])-1; //可插入的0
sum+=j;
a[i-1]-=j;
a[i]-=j;
}
sum+=a[n]-1; //n之后可以插入的0
cout<<sum;
return 0;
}
E.soyorin的数组操作(easy)
题目:
解题思路:
每次操作只能选择偶数个,当n是偶数时,假设操作无数次后,必然是递增的;
当n是奇数时,需要满足前一个数小于后一个数,同时要使前一个数达到小于后一个数的最大值。
代码如下:
#include <bits/stdc++.h>
#include <iostream>
#define int long long
#define endl '\n'
using namespace std;
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
cin>>t;
while(t--)
{
int n,a[100005],flag=1;
cin>>n;
for(int i=1; i<=n; i++)
cin>>a[i];
if(n%2==0)
{
cout<<"YES"<<endl; //n是偶数时显然可以
continue;
}
int s=0; //以下是n为奇数的情况
for(int i=n-1; i>=1; i--)
{
a[i]+=s*i;
if(a[i]>a[i+1]) //必须满足前面的数小于后面的数
{
flag=0;
break;
}
if(i%2==0)
{
int k=(a[i+1]-a[i])/i;
a[i]+=k*i; //尽量使a[i]达到小于a[i+1]的最大值
s+=k;
}
}
if(flag)cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}
G.sakiko的排列构造(easy)
H.sakiko的排列构造(hard)
题目:(hard解法easy同样适用)
解题思路:
可以将排列p切分为几个区间,使每个区间的都是相同的质数,因此求出1~2n之间的质数,然后从后往前遍历。
代码如下:
#include <bits/stdc++.h>
#include <iostream>
#define int long long
#define endl '\n'
using namespace std;
bool not_prime[2000005]={0};
int a[2000005],prime[2000005];
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n,t,z=0;
cin>>n;
for(int i=2;i<=2*n;++i) //埃式筛求出2*n以内所有质数
{
if(!not_prime[i])
{
prime[++z]=i;
for(int j=i*i;j<=2*n;j+=i)
not_prime[j]=1;
}
}
t=n;
while(t>=1)
{
int x=prime[z],y=t; //从最大质数开始,找出几个数使它们的和等于该质数
z--;
for(int i=y;x-i<=y&&i>=1;i--)
{
a[i]=x-i;
t--;
}
}
for(int i=1;i<=n;i++)
cout<<a[i]<<' ';
return 0;
}
J.rikki的数组陡峭值
题目:
解题思路:(贪心+区间合并)
代码如下:
#include <bits/stdc++.h>
#include <iostream>
#define int long long
#define endl '\n'
using namespace std;
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n,r,l,x,y,sum=0;
cin>>n;
cin>>l>>r;
for(int i=1;i<n;i++)
{
cin>>x>>y;
if(x>=r) sum+=x-r,l=r=x;
else if(y<=l) sum+=l-y,l=r=y;
else l=max(l,x),r=min(r,y);
}
cout<<sum;
return 0;
}
M.mutsumi的排列连通
题目:
解题思路:(感觉这题和之前的关鸡挺像的)
分成的两个连通块不一定是矩形,
最好情况就是需要删除同一直线或对角线的两个相同数字;
最坏情况需要删除同一直线上的两个不同数字。
代码如下:
#include <bits/stdc++.h>
#include <iostream>
#define int long long
#define endl '\n'
using namespace std;
void solve()
{
int n,a[100005],b[100005];
cin>>n;
for(int i=1; i<=n; i++)
cin>>a[i];
for(int i=1; i<=n; i++)
cin>>b[i];
if(n==1)
{
cout<<-1<<endl;
return;
}
if(n==2)
{
if(a[1]==b[1])cout<<-1<<endl;
else cout<<1<<endl;
return;
}
for(int i=2; i<=n-1; i++)
{
if(a[i]==b[i])
{
cout<<1<<endl;
return;
}
if(a[i-1]==b[i])
{
cout<<1<<endl;
return;
}
if(a[i+1]==b[i])
{
cout<<1<<endl;
return;
}
if(a[i]==b[i-1])
{
cout<<1<<endl;
return;
}
if(a[i]==b[i+1])
{
cout<<1<<endl;
return;
}
}
cout<<2<<endl;
return;
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
cin>>t;
while(t--)
{
solve();
}
return 0;
}