目录
A.mutsumi的质数合数
简单数学知识:1既不是质数也不是合数
void solve(){
cin>>n;
int ans=0;
for(int i=1;i<=n;i++){
int x; cin>>x;
if(x==1) continue;
ans++;
}
cout<<ans<<endl;
return ;
}
B.tomorin的字符串迷茫值
性质dp
观察题目本质,由于不能连续删除所以留下带有指定字符的
"mygo","m_ygo","my_go","myg_o","m_y_go","m_yg_o","my_g_o","m_y_g_o"只有这些情况,所以在这样的情况下后面周围的随便选(周围的随便选其实就是斐波那契数列),然后乘积起来即可
void solve(){
string s; cin>>s;
n=s.size();
vector<int> dp(n+1,1);
dp[1]=2;
for(int i=2;i<=n;i++) dp[i]=(dp[i-1]+dp[i-2])%mod;
vector<string> t={"mygo","m_ygo","my_go","myg_o","m_y_go","m_yg_o","my_g_o","m_y_g_o"};
int ans=0;
for(int i=0;i<n;i++){
for(auto&v:t){
string c=s.substr(i,v.size());
int ok=0;
for(int j=0;j<v.size();j++){
if(v[j]=='_') ok++;
else if(v[j]==c[j]) ok++;
}
if(ok==v.size())(ans+=dp[i]*dp[n-i-ok]%mod)%=mod;
}
}
cout<<ans<<endl;
return ;
}
C.anon的私货
思维贪心,我们直接按照要求来排放最多的0即可排了之后对当前数减去后面的排了的0注意顶一个数和最后一个数都是可以扩充的
void solve(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
LL ans=0;
a[0]=2e9;
for(int i=1;i<=n;i++){
int x=min(a[i-1]-1,a[i]-1);
ans+=x;
a[i]-=x;
}
ans+=max(0,a[n]-1);
cout<<ans<<endl;
return ;
}
E.F.soyorin的数组操作(easy & hard)
首先对于这种题目发现性质,可以明显得知如果是1或者是偶数是一定有解的,对于奇数我们如何操作呢,可以发现最后一个数是奇数是不可以操作的也就是我们的限高,然后我们发现操作的越多是越有利的,如果我们从前面开始的话不可知上限由于后面的数还会变化,但是我们从后面开始的话上限是可知的,同时可以保留每次的处理,所以我们倒着来每次都处理到上限位置即可,然后判断是否有解,对于求解操作次数我们发现如果是有解的话那么一定就是每一次操作都可以减少最大的一次所以我们的操作次数就是其中的最大差值
void solve(){
res=0;
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=2;i<=n;i++){
res=max(res,a[i-1]-a[i]);
}
if(n%2==0 || n==1){
cout<<res<<endl;
return ;
}
LL cnt=0;
for(int i=n;i>=1;i--){
a[i]+=cnt*i;
if(i%2==0){
LL t=max(0ll,(a[i+1]-a[i])/i);
a[i]+=t*i;
cnt+=t;
}
}
bool ok =true;
for(int i=2;i<=n;i++)
if(a[i]<a[i-1]){
ok=false;
}
cout<<(ok ? res : -1)<<endl;
return ;
}
G.H.sakiko的排列构造(easy & hard)
规律发现和打表思考题
我们可以发现如果说是easy的范围我们可以使用匈牙利算法来直接解决问题,对于hard的问题我们要思考是不是具有性质基本上就是o(n)的解决题目,我们思考如果说1+x是质数那么这里面的数都是可以组合为质数的 2+x-1=3+x-2=...,假设 x+1+n也是质数那么整个题目就可以直接解决了,对于判断质数可以使用筛法也可以使用直接判断,所以我们发现(打表)一定是可以找到的
void intn(int n)
{
for(int i=2;i<=n;i++){
if(!st[i]) primes[cnt++]=i;
for(int j=0;primes[j]<=n/i;j++){
st[i*primes[j]]=true;
if(i%primes[j]==0) break;
}
}
}
void solve(){
cin>>n;
intn(2*n+5);
int r=n;
for(int i=n;i>=1;i--){
if(!st[i+r]){
for(int j=i;j<=r;j++){
ans[j]=i+r-j;
}
r=i-1;
}
}
for(int i=1;i<=n;i++) cout<<ans[i]<<' ';
cout<<endl;
return ;
}
I.rikki的最短路
我们发现问题的核心是相对位置的确定以及是不是第一次就可以直接去A,搞清楚之后就很简单
void solve(){
LL t,a,k; cin>>t>>a>>k;
if(a<=k && a>=-k){// 看到了a 到a然后去t
LL ans = abs(a)+abs(t-a);
cout<<ans<<endl;
}
else{
if(abs(a)>=abs(t)){
if((a>=0 && t>=0) || (a<=0 && t<=0)){// 一侧
LL ans = abs(a)+abs(a-t);
cout<<ans<<endl;
}
else{// 不是同一侧
LL ans = 3*abs(t) + 2*abs(a);
cout<<ans<<endl;
}
}
else{
if((a>=0 && t>=0) || (a<=0 && t<=0)){// 一侧
LL ans = abs(t);
cout<<ans<<endl;
}
else{// 两侧
LL ans = 3*abs(t) + 2*abs(a);
cout<<ans<<endl;
}
}
}
return ;
}
J.rikki的数组陡峭值
贪心求解基本上我们可以知道如果第一个点确定之后我们直接围绕他开始贪心即可,而我们发现只要是按照区间相交的操作来维护直接就可以得到答案所以可以这样贪心
PII w[N];
void solve(){
cin>>n;
for(int i=1;i<=n;i++){
int l,r; cin>>l>>r;
w[i]={l,r};
}
int L=w[1].first,R=w[1].second;
LL ans=0;
for(int i=2;i<=n;i++){
auto [l,r]=w[i];
if(l>R){
ans+=l-R;
L=R=l;
}
else if(r<L){
ans+=L-r;
L=R=r;
}
else{
L=max(L,l);
R=min(R,r);
}
}
cout<<ans<<endl;
return ;
}
K.soyorin的通知
注意题目也就是第一个人一定是固定需要话这么多才能开始操作的,然后对于至多的意思就是小于他的也是可以操作的所以我们都要进行处理,然后对于1,p也是可以处理的搞清楚题目的整个意思后整个题就是一个完全背包了
LL w[M];
LL f[M];
void solve(){
cin>>n>>p;
for(int i=1;i<=n;i++) w[i]=1e18;
for(int i=1;i<=n;i++){
int x,y; cin>>x>>y;
for(int j=1;j<=min(y,n);j++){
w[j]=min(w[j],x);
}
}
for(int i=0;i<=n;i++) f[i]=3e18;
f[1]=p;
w[1]=min(w[1],p);
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++){
f[j]=min(f[j],f[j-i]+w[i]);// 多次更新
}
cout<<f[n]<<endl;
return ;
}
L.anon的星星
暴力
我们可以发现数据范围很小直接暴力即可
void solve(){
cin>>n>>m;
for(int i=0;i<=n;i++){
int ans=i-(n-i);
if(ans==m){
cout<<i<<' '<<n-i<<endl;
return ;
}
}
cout<<-1<<endl;
return ;
M.mutsumi的排列连通
思考一下如果要不连通最多就是删除中间位置的两个数即可,也就是答案的上限就是2,
乐意思考到如果是1是无解的如果是 12 同时是排列整齐的也是无解
接着我们考虑一个的情况,
1.(在中间)同一个位置的两个数是一样的
2.这样的a,或者是b都是一次
所以按照要求模拟即可
void solve(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) cin>>b[i];
if(n==2){
if(a[1]==b[1]){
cout<<-1<<endl;
}
else{
cout<<1<<endl;
}
return ;
}
if(n==1){
cout<<-1<<endl;
return ;
}
else{
for(int i=2;i<n;i++){
if(a[i]==b[i]){
cout<<1<<endl;
return ;
}
}
for(int i=1;i<=n;i++){
if(i+1<=n && a[i]==b[i+1]){
cout<<1<<endl;
return ;
}
if(i-1>=1 && a[i]==b[i-1]){
cout<<1<<endl;
return ;
}
}
cout<<2<<endl;
}
return ;
}