winter week5 day3

2024牛客寒假算法基础集训营5

A

mutsumi的质数合数

思路:1既不是质数也不是合数

查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
//#define int __int128
#define double long double
typedef pair<int,int>PII;
typedef pair<string,int>PSI;
typedef pair<string,string>PSS;
const int N=1e5+5,INF=0x3f3f3f3f,mod=1e9+7,Mod=998244353;
const int MAXN=1e8+5;
const double eps=1e-9;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};

void solve() {
    int n;
    cin>>n;
    int m=n;
    for(int i=0;i<n;++i){
        int x;
        cin>>x;
        if(x==1)m--;
    }
    cout<<m;
}


signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int t=1;
//    cin>>t;
    while(t--){
        solve();
    }
    return 0;
}

B

tomorin的字符串迷茫值

思路1:由于不能删连续的两个字符,则一个mygo带来的贡献在原串中的形式有8种(在mygo中任意插空格),其余位置可以任意删,枚举所有形式的贡献即可。f[i]表示一段长度为i且可以任意操作的串的删除总数,可以推出f[i]=f[i-1]+f[i-2],分别为不删第i个和删第i个

查看代码
 #include<bits/stdc++.h>
using namespace std;
#define int long long
//#define int __int128
#define double long double
typedef pair<int,int>PII;
typedef pair<string,int>PSI;
typedef pair<string,string>PSS;
const int N=1e6+5,INF=0x3f3f3f3f,mod=1e9+7,Mod=998244353;
const int MAXN=1e8+5;
const double eps=1e-9;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};
string s[8]={"mygo","m ygo","my go","myg o","m y go","m yg o","my g o","m y g o"};

void solve() {
    string x;
    cin>>x;
    int n,ans=0;
    n=x.size();
    vector<int>f(n+1);
    f[0]=1,f[1]=2;
    for(int i=2;i<=n;++i)f[i]=(f[i-1]+f[i-2])%mod;
    auto check=[](string a,string b){
        for(int i=0;i<b.size();++i){
            if(b[i]==' ')continue;
            if(a[i]!=b[i])return false;
        }
        return true;
    };
    for(int i=0;i<n;++i){
        for(int j=0;j<8;++j){
            if(i+s[j].size()-1>=n)continue;
            string u=x.substr(i,s[j].size());
            if(check(u,s[j]))ans=(ans+f[i]*f[n-i-s[j].size()]%mod)%mod;
        }
    }
    cout<<ans;
}

signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int t=1;
//    cin>>t;
//    init();
    while(t--){
        solve();
    }
    return 0;
}

 

思路2:f[i][j]表示前i个里第i个选(不删)或不选(删)的mygo的方案数

不选:f[i][0]=f[i-1][1]

选:f[i][1]=f[i-1][1]+f[i-1][0]+s[i]=='o'时前i-1里前缀为myg的方案数

对于前i-1里前缀为myg的方案数可由前缀为my表示,依次类推,更新前缀为任意值、m、my、myg的方案数

查看代码
 #include<bits/stdc++.h>
using namespace std;
#define int long long
//#define int __int128
#define double long double
typedef pair<int,int>PII;
typedef pair<string,int>PSI;
typedef pair<string,string>PSS;
const int N=1e6+5,INF=0x3f3f3f3f,mod=1e9+7,Mod=998244353;
const int MAXN=1e8+5;
const double eps=1e-9;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};
string s[8]={"mygo","m ygo","my go","myg o","m y go","m yg o","my g o","m y g o"};
int f[N][2][4];
void solve() {
    string x;
    cin>>x;
    int n=x.size();
    x.insert(x.begin(),' ');
    if(x[1]=='m'){
        f[1][1][1]=f[1][0][0]=1;
    }else{
        f[1][1][0]=f[1][0][0]=1;
    }
    for(int i=2;i<=n;++i){
        f[i][0][0]=f[i-1][1][0];
        f[i][0][1]=f[i-1][1][1];
        f[i][0][2]=f[i-1][1][2];
        f[i][0][3]=f[i-1][1][3];

        f[i][1][0]=(f[i-1][1][0]*(x[i]!='m')+f[i-1][1][1]*(x[i]!='m'&&x[i]!='y')+f[i-1][1][2]*(x[i]!='m'&&x[i]!='g')+f[i-1][1][3]*(x[i]!='m')
                  + f[i-1][0][0]*(x[i]!='m')+f[i-1][0][1]*(x[i]!='m'&&x[i]!='y')+f[i-1][0][2]*(x[i]!='m'&&x[i]!='g')+f[i-1][0][3]*(x[i]!='m'))%mod;
        f[i][1][1]=((x[i]=='m')*(f[i-1][1][0]+f[i-1][1][1]+f[i-1][1][2]+f[i-1][1][3]+f[i-1][0][0]+f[i-1][0][1]+f[i-1][0][2]+f[i-1][0][3]))%mod;
        f[i][1][2]=(f[i-1][1][1]+f[i-1][0][1])*(x[i]=='y')%mod;
        f[i][1][3]=(f[i-1][1][2]+f[i-1][0][2])*(x[i]=='g')%mod;
    }
    vector<array<int,2>>g(n+1);
    for(int i=1;i<=n;++i){
        g[i][0]=g[i-1][1];
        g[i][1]=(g[i-1][0]+g[i-1][1]+(x[i]=='o')*(f[i-1][1][3]+f[i-1][0][3]))%mod;
    }
    cout<<(g[n][0]+g[n][1])%mod;
}

signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int t=1;
//    cin>>t;
//    init();
    while(t--){
        solve();
    }
    return 0;
}

 

C

anon的私货

思路:模拟

对于一个大于1的数x,x减去1则可以在x旁添加1个0,最多添加x-1个,这样x和这些0这一段数的平均值为1;由于添加的0也会影响到原本x旁边的数y,那就取min(x-1,y-1),让x和y都同时减,统计总共减的个数

查看代码
 #include<bits/stdc++.h>
using namespace std;
#define int long long
//#define int __int128
#define double long double
typedef pair<int,int>PII;
typedef pair<string,int>PSI;
typedef pair<string,string>PSS;
const int N=1e5+5,INF=0x3f3f3f3f,mod=1e9+7,Mod=998244353;
const int MAXN=1e8+5;
const double eps=1e-9;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};

void solve() {
    int n;
    cin>>n;
    vector<int>a(n);
    for(int i=0;i<n;++i)cin>>a[i];
    int ans=0;
    ans+=a[0]-1;
    for(int i=1;i<n-1;++i){
        int c=min(a[i],a[i+1])-1;
        ans+=c;
        a[i]-=c,a[i+1]-=c;
    }
    if(n!=1)
    ans+=a[n-1]-1;
    cout<<ans;
}

signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int t=1;
//    cin>>t;
    while(t--){
        solve();
    }
    return 0;
}

E

soyorin的数组操作(easy)

思路:首先偶数肯定是可以的,每次相邻数的差加一,可以操作无限次。其次是奇数,最后一个数是变不了的,那就是看能否让操作次数尽可能少,且倒数第二个数要不大于最后一个数。这里可以考虑倒着处理,由于最后一个数不能变,那就可以由它与前一个数的差值求出前一个数最多能操作多少次,往前同理。最后看序列是否非递减即可

查看代码
 #include<bits/stdc++.h>
using namespace std;
#define int long long
//#define int __int128
#define double long double
typedef pair<int,int>PII;
typedef pair<string,int>PSI;
typedef pair<string,string>PSS;
const int N=1e6+5,INF=0x3f3f3f3f,mod=1e9+7,Mod=998244353;
const int MAXN=1e8+5;
const double eps=1e-9;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};

void solve() {
    int n;
    cin>>n;
    vector<int>ve(n+1),cnt(n+1);
    for(int i=1;i<=n;++i){
        cin>>ve[i];
    }
    if(n%2==0||n==1)cout<<"YES\n";
    else{
        int k=0;
        for(int i=n-1;i>=1;--i){
            if(i%2==0){
                int now=ve[i]+k*i;
                if(now>ve[i+1]){
                    cout<<"NO\n";
                    return ;
                }
                k+=(ve[i+1]-now)/i;
            }
            ve[i]+=k*i;
            if(ve[i]>ve[i+1]){
                cout<<"NO\n";
                return ;
            }
        }
        cout<<"YES\n";
    }
}

signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int t=1;
    cin>>t;
//    init();
    while(t--){
        solve();
    }
    return 0;
}

F

soyorin的数组操作(hard)

这道题很容易被easy影响到。最初想esay的做法时其实就是hard的答案😅,就是最大相邻差值,但是easy写错了好几个思路,写hard的时候就没往那方面想,但是这道还是得会easy才能出hardqwq。

思路:先和easy一样判断是否可以。然后就是求最少次数,一个数的操作次数即为它与前一个数的差值,每个数如此,并且可以覆盖其前面的数的操作,假如前面有个数操作一次,当前这个数也要一次,就可以由当前这个数的操作覆盖前面那个数的操作,实际上总共只需要一次。那其实就是求最大相邻差值

查看代码
 #include<bits/stdc++.h>
using namespace std;
#define int long long
//#define int __int128
#define double long double
typedef pair<int,int>PII;
typedef pair<string,int>PSI;
typedef pair<string,string>PSS;
const int N=1e6+5,INF=0x3f3f3f3f,mod=1e9+7,Mod=998244353;
const int MAXN=1e8+5;
const double eps=1e-9;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};

void solve() {
    int n,ans=0;
    cin>>n;
    vector<int>ve(n+1),cnt(n+1);
    for(int i=1;i<=n;++i){
        cin>>ve[i];
        if(i>1)ans=max(ans,ve[i-1]-ve[i]);
    }
    if(n%2==0||n==1) {  }
    else{
        int k=0;
        for(int i=n-1;i>=1;--i){
            if(i%2==0){
                int now=ve[i]+k*i;
                if(now>ve[i+1]){
                    cout<<"-1\n";
                    return ;
                }
                k+=(ve[i+1]-now)/i;
            }
            ve[i]+=k*i;
            if(ve[i]>ve[i+1]){
                cout<<"-1\n";
                return ;
            }
        }
    }
    cout<<ans<<'\n';
}

signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int t=1;
    cin>>t;
//    init();
    while(t--){
        solve();
    }
    return 0;
}

G

同hard

sakiko的排列构造(easy)

查看代码
 #include<bits/stdc++.h>
using namespace std;
#define int long long
//#define int __int128
#define double long double
typedef pair<int,int>PII;
typedef pair<string,int>PSI;
typedef pair<string,string>PSS;
const int N=1e6+5,INF=0x3f3f3f3f,mod=1e9+7,Mod=998244353;
const int MAXN=1e8+5;
const double eps=1e-9;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};
int st[2*N];
int primes[2*N],cnt;
void init(){
    for(int i=2;i<=2*N;++i){
        if(!st[i])primes[cnt++]=i;
        for(int j=0; primes[j]*i<=2*N;++j){
            st[primes[j]*i]=true;
            if(i%primes[j]==0)break;
        }
    }
}
void solve() {
    int n;
    cin>>n;
    vector<int>ans(n+1);
    for(int i=n,r=n;i>0;--i){
        if(!st[i+r]){
            for(int j=i,p=r;j<=r;++j)ans[j]=p--;
            r=i-1;
        }
    }
    for(int i=1;i<=n;++i)cout<<ans[i]<<' ';
}

signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int t=1;
//    cin>>t;
    init();
    while(t--){
        solve();
    }
    return 0;
}

H

思路:如果x+y为质数(x<y),在位置{x,x+1,...,y-1,y}可以构造出{y,y-1,...,x+1,x},使得每个数的值为x+y

先预处理出2n以内的质数,从n往前一段一段的找x、y

sakiko的排列构造(hard)

查看代码
 #include<bits/stdc++.h>
using namespace std;
#define int long long
//#define int __int128
#define double long double
typedef pair<int,int>PII;
typedef pair<string,int>PSI;
typedef pair<string,string>PSS;
const int N=1e6+5,INF=0x3f3f3f3f,mod=1e9+7,Mod=998244353;
const int MAXN=1e8+5;
const double eps=1e-9;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};
int st[2*N];
int primes[2*N],cnt;
void init(){
    for(int i=2;i<=2*N;++i){
        if(!st[i])primes[cnt++]=i;
        for(int j=0; primes[j]*i<=2*N;++j){
            st[primes[j]*i]=true;
            if(i%primes[j]==0)break;
        }
    }
}
void solve() {
    int n;
    cin>>n;
    vector<int>ans(n+1);
    for(int i=n,r=n;i>0;--i){
        if(!st[i+r]){
            for(int j=i,p=r;j<=r;++j)ans[j]=p--;
            r=i-1;
        }
    }
    for(int i=1;i<=n;++i)cout<<ans[i]<<' ';
}

signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int t=1;
//    cin>>t;
    init();
    while(t--){
        solve();
    }
    return 0;
}

I

rikki的最短路

思路:分类讨论

查看代码
 #include<bits/stdc++.h>
using namespace std;
#define int long long
//#define int __int128
#define double long double
typedef pair<int,int>PII;
typedef pair<string,int>PSI;
typedef pair<string,string>PSS;
const int N=1e5+5,INF=0x3f3f3f3f,mod=1e9+7,Mod=998244353;
const int MAXN=1e8+5;
const double eps=1e-9;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};

void solve() {
    int t,a,k;
    cin>>t>>a>>k;
    int ans;
    if(t*a>=0){
        t=abs(t),a=abs(a);
        if(a<=t)ans=t;
        else{
            ans=2*a-t;
        }
    }else{
        t=abs(t),a=abs(a);
        if(a<=k)ans=2*a+t;
        else ans=3*t+2*a;
    }
    cout<<ans;
}

signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int t=1;
//    cin>>t;
    while(t--){
        solve();
    }
    return 0;
}

J

rikki的数组陡峭值

思路:贪心+dp

当相邻两个数相同时差最小,那就让相同的数尽可能多。若相邻两个数的区间相交说明可以取相同的数,可以取两个区间的交集,那就遍历所有区间,将可以合并的区间合并,统计所有合并后的区间。统计后的区间相邻都是没有交集的,也就是选出来的相邻数一定会有差值。一个区间中选最大和最小是最优的,那就用dp求就好了

查看代码
 #include<bits/stdc++.h>
using namespace std;
#define int long long
//#define int __int128
#define double long double
typedef pair<int,int>PII;
typedef pair<string,int>PSI;
typedef pair<string,string>PSS;
const int N=1e6+5,INF=0x3f3f3f3f,mod=1e9+7,Mod=998244353;
const int MAXN=1e8+5;
const double eps=1e-9;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};

void solve() {
    int n;
    cin>>n;
    vector<PII>ve(n),g;
    for(int i=0;i<n;++i){
        cin>>ve[i].first>>ve[i].second;
    }
    int l=ve[0].first,r=ve[0].second;
    for(int i=1;i<n;++i){
        if(ve[i].second>=l&&ve[i].first<=r){
            l=max(l,ve[i].first),r=min(r,ve[i].second);
        }else{
            g.push_back({l,r});
            l=ve[i].first,r=ve[i].second;
        }
    }
    g.push_back({l,r});
    vector<array<int,2>>f(g.size());
    for(int i=1;i<g.size();++i){
        f[i][0]=min(f[i-1][0]+abs(g[i].first-g[i-1].first),f[i-1][1]+abs(g[i].first-g[i-1].second));
        f[i][1]=min(f[i-1][0]+abs(g[i].second-g[i-1].first),f[i-1][1]+abs(g[i].second-g[i-1].second));
    }
    cout<<min(f[g.size()-1][0],f[g.size()-1][1]);
}

signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int t=1;
//    cin>>t;
//    init();
    while(t--){
        solve();
    }
    return 0;
}

K

soyorin的通知

思路:其实是完全背包,没有限制被传播的是谁,每个人的花费以及传播人数都知道,并且可以多次传播,就是求完全背包,然后至少要有一个人是花费p的

查看代码
 #include<bits/stdc++.h>
using namespace std;
#define int long long
//#define int __int128
#define double long double
typedef pair<int,int>PII;
typedef pair<string,int>PSI;
typedef pair<string,string>PSS;
const int N=1e6+5,INF=0x3f3f3f3f,mod=1e9+7,Mod=998244353;
const int MAXN=1e8+5;
const double eps=1e-9;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};

void solve() {
    int n,p;
    cin>>n>>p;
    vector<int>dp(n+1,INF);
    dp[0]=0;
    for(int i=1;i<=n;++i){
        int a,b;
        cin>>a>>b;
        if(b>=n)b=n-1;
        for(int j=0;j<=n;++j)
            dp[j]=min(dp[j],dp[max(0ll,j-b)]+a);
    }
    int ans=INF;
    for(int i=0;i<n;++i){
        ans=min(ans,dp[i]+(n-i)*p);
    }
    cout<<ans;
}

signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int t=1;
//    cin>>t;
//    init();
    while(t--){
        solve();
    }
    return 0;
}

L

anon的星星

思路:推式子

查看代码
 #include<bits/stdc++.h>
using namespace std;
#define int long long
//#define int __int128
#define double long double
typedef pair<int,int>PII;
typedef pair<string,int>PSI;
typedef pair<string,string>PSS;
const int N=1e5+5,INF=0x3f3f3f3f,mod=1e9+7,Mod=998244353;
const int MAXN=1e8+5;
const double eps=1e-9;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};

void solve() {
    //a+b=n
    //a-b=x
    //a=(n+x)/2;
    //b=n-a;
    //b=(n-x)/2;
    int n,x;
    cin>>n>>x;
    if((n+x)%2||(n-x)%2){
        cout<<-1;
    }else{
        int a=(n+x)/2,b=n-a;
        cout<<a<<' '<<b;
    }
}


signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int t=1;
//    cin>>t;
    while(t--){
        solve();
    }
    return 0;
}

M

mutsumi的排列连通

思路:分成至少两个连通块其实就是形成下面三种情况,如果存在下面位置的相同数字则答案为1,否则答案为2,可以通过两种数形成下面情况

           
           
查看代码
 #include<bits/stdc++.h>
using namespace std;
#define int long long
//#define int __int128
#define double long double
typedef pair<int,int>PII;
typedef pair<string,int>PSI;
typedef pair<string,string>PSS;
const int N=1e5+5,INF=0x3f3f3f3f,mod=1e9+7,Mod=998244353;
const int MAXN=1e8+5;
const double eps=1e-9;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};

void solve() {
    //1234
    //3412
    int n;
    cin>>n;
    vector<int>a(n+1),b(n+1);
    for(int i=1;i<=n;++i){
        cin>>a[i];
    }
    for(int i=1;i<=n;++i){
        int x;
        cin>>x;
        b[x]=i;
    }
    int ans=INF;
    for(int i=1;i<=n;++i){
        int c=abs(i-b[a[i]]);
        if(c==0&&(i==1||i==n))continue;
        if(c==0)c++;
        ans=min(ans,c);
    }
    if(ans==INF)cout<<-1<<'\n';
    else cout<<min(2ll,ans)<<'\n';
}

signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int t=1;
    cin>>t;
    while(t--){
        solve();
    }
    return 0;
}

 

posted @ 2024-02-25 21:33  bible_w  阅读(8)  评论(0编辑  收藏  举报