寒假训练第四周(牛客训练营)
E-漂亮数组_2024牛客寒假算法基础集训营4 (nowcoder.com)
这题想多了,以为是一个dp优化,没想到贪心即可,dp比较弱,赶紧优化
题解:找一个区间满足k倍即可,我们直接累加然后模k如果出现两次模k等于同一个数那么这个区间就是k的倍数记录即可
简单贪心,没想到
#include <bits/stdc++.h> //#pragma GCC optimize("Ofast") #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <queue> #include <cmath> //#define double long double #define int long long #define endl '\n' using namespace std; const int N=2e5+9,M=1e1; const int INF = 0x3f3f3f3f3f3f3f3f; const int mod=998244353; typedef pair<int,int> PII; void solve() { int n,k; cin>>n>>k; map<int,int> mp; mp[0]=1; int sum=0; int ans=0; for(int i=1;i<=n;i++) { int x; cin>>x; sum+=x; int p=sum%k; if(mp[p]) { ans++; mp.clear(); sum=0; mp[0]=1; continue; } mp[p]=1; } cout<<ans<<endl; } signed main(){ std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int T=1; // cin>>T; while(T--){ solve(); } return 0; }
H-sakiko的排列构造(hard)_2024牛客寒假算法基础集训营5 (nowcoder.com)
题解: (补题没打)
这种题必定分段处理,我们可以想到,要是某一段末尾数加开头数等于一个素数,那么这一段倒着排一下就可以了,所以我们倒着处理就行了,分成一段一段的,最后那个1无论怎么样都可以成素数
用递归或者栈都可以
#include <bits/stdc++.h> //#pragma GCC optimize("Ofast") #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <queue> #include <cmath> //#define double long double #define int long long #define endl '\n' using namespace std; const int N=1e7+9,M=1e1; const int INF = 0x3f3f3f3f3f3f3f3f; const int mod=998244353; typedef pair<int,int> PII; bool isprime[N]; // isprime[i]表示i是不是素数 int prime[N]; // 现在已经筛出的素数列表 int cnt; // 已经筛出的素数个数 void euler() { memset(isprime, true, sizeof(isprime)); // 先全部标记为素数 isprime[1] = false; // 1不是素数 for(int i = 2; i <= N; ++i) // i从2循环到n(外层循环) { if(isprime[i]) prime[++cnt] = i; // 如果i没有被前面的数筛掉,则i是素数 for(int j = 1; j <= cnt && i * prime[j] <= N; ++j) // 筛掉i的素数倍,即i的prime[j]倍 // j循环枚举现在已经筛出的素数(内层循环) { isprime[i * prime[j]] = false; // 倍数标记为合数,也就是i用prime[j]把i * prime[j]筛掉了 if(i % prime[j] == 0) break; // 最神奇的一句话,如果i整除prime[j],退出循环 // 这样可以保证线性的时间复杂度 } } } void solve() { int n; cin>>n; if(isprime[n+1]) { for(int i=n;i>=1;i--) { cout<<i<<" "; } return; } else { int now=n; stack<int> a; for(int i=now-1;i>=1;i--) { if(isprime[i+now]) { for(int j=i;j<=now;j++) { a.push(j); } now=i-1; } } int k=a.size(); for(int i=1;i<=k;i++) { cout<<a.top()<<" "; a.pop(); } cout<<endl; } } signed main(){ std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int T=1; // cin>>T; while(T--){ euler(); solve(); } return 0; }
C-anon的私货_2024牛客寒假算法基础集训营5 (nowcoder.com)、
补题(缺席)
题解:这道题思路出的很快,就是有个坑点
两个数中间插0,我们直接按照最小的数的权值减一插入即可
但是记得对另外一个数减减,因为插0会影响后面的值的可插0个数
这个题坑在 第一个数前面也可以插0,所以要处理一下第一个数
#include <bits/stdc++.h> //#pragma GCC optimize("Ofast") #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <queue> #include <cmath> //#define double long double #define int long long #define endl '\n' using namespace std; const int N=1e7+9,M=1e1; const int INF = 0x3f3f3f3f3f3f3f3f; const int mod=998244353; typedef pair<int,int> PII; int a[N]; void solve() { int n; cin>>n; for(int i=1;i<=n;i++) { cin>>a[i]; } int ans=0; if(a[1]>1) { ans+=a[1]-1; a[1]=1; } a[n+1]=INF; for(int i=1;i<=n;i++) { int x=min(a[i],a[i+1]); x--; a[i]-=x; a[i+1]-=x; ans+=x; } cout<<ans<<endl; } signed main(){ std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int T=1; // cin>>T; while(T--){ solve(); } return 0; }
I-时空的交织_2024牛客寒假算法基础集训营6 (nowcoder.com)
题解:这道题就是让你对行和列分别算一个最优区间,然后乘在一起就可以了
主要是这个区间怎么算
我们可以发现行和列可能是两个负数或者两个正数乘起来可能就最大
所以我们要分别处理,一个如果加上这个数小于0那么就需要更新,初值,然后注意两边都要进行比大小,因为可能有一边不进判断里,当全负数的情况时
然后就是另外一个大于0更新,相反的,和上面同理
#include <bits/stdc++.h> #pragma GCC optimize("Ofast") #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <queue> #include <cmath> //#define double long double #define int long long #define endl '\n' using namespace std; const int N=1e6+10,M=1e9; const int INF = 0x3f3f3f3f3f3f3f3f; const int mod=998244353; typedef pair<int,int> PII; int a[N]; int b[N]; void solve() { int n,m; cin>>n>>m; int hmi=INF,lmi=INF; int ans1=-INF,ans2=-INF; for(int i=1,x=0,y=0;i<=n;i++) { cin>>a[i]; if(x+a[i]>=0) { x+=a[i]; ans1=max(ans1,x); } else{ ans1=max(ans1,a[i]); x=0; } if(y+a[i]<=0) { y+=a[i]; hmi=min(hmi,y); } else{ hmi=min(hmi,a[i]); y=0; } } for(int i=1,x=0,y=0;i<=m;i++) { cin>>b[i]; if(x+b[i]>=0) { x+=b[i]; ans2=max(ans2,x); } else { ans2=max(ans2,b[i]); x=0; } if(y+b[i]<=0) { y+=b[i]; lmi=min(y,lmi); } else { lmi=min(b[i],lmi); y=0; } } cout<<max({ans1*ans2,lmi*hmi,ans1*lmi,ans2*hmi}); } signed main(){ std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int T=1; // cin>>T; while(T--){ solve(); } return 0; }
J-绝妙的平衡_2024牛客寒假算法基础集训营6 (nowcoder.com)
题解:这是一个树题
我们只需要贪心处理一下每一个红色节点的数的权值之和就可以了,首先存一下每个节点的子节点,然后首先判断一下死否可以把这个树按照要求构造好
如果一棵树红色节点下没有白色节点,那么就不能构造出来,输出-1即可
如果可以,跑一边深搜,然后从叶子节点开始,每一个点都向上跑即可,不足加加即可
#include <bits/stdc++.h> #pragma GCC optimize("Ofast") #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <queue> #include <cmath> //#define double long double #define int long long #define endl '\n' using namespace std; const int N=1e6+10,M=1e9; const int INF = 0x3f3f3f3f3f3f3f3f; const int mod=998244353; typedef pair<int,int> PII; int cnt[N]; vector<int> v[N]; int len[N]; int a[N]; void dfs(int u) { int ans=1; for(auto it:v[u]) { dfs(it); if(!cnt[it]) ans+=len[it]; } if(cnt[u]) { if(ans%3==2) { a[u]++; } else if(ans%3==1) { a[u]++; a[v[u][0]]++; } } len[u]=ans; } void solve() { int n; cin>>n; string s; cin>>s; for(int i=0;i<s.size();i++) { if(s[i]=='R') cnt[i+1]=1; } for(int i=2;i<=n;i++) { int x; cin>>x; v[x].push_back(i); } int f=0; for(int i=1;i<=n;i++) { len[i]=1;a[i]=1; f=0; for(auto it:v[i]) { if(!cnt[it]) { f=1; break; } } if(cnt[i] && f==0) { cout<<-1<<endl; return; } } dfs(1); for(int i=1;i<=n;i++) cout<<a[i]; } signed main(){ std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int T=1; // cin>>T; while(T--){ solve(); } return 0; }
G-人生的起落_2024牛客寒假算法基础集训营6 (nowcoder.com)
题解:这道题主要看细节
首先我们知道最简单的构造是2 1 2 1 2
所以按照这种构造即可,注意要判断一下-1情况 k*2+1>n 和n+k>=s 不行,可以带入 2 1 2,就可以知道了
然后就是正常构造 余下的数全部放在等于的n里就可用了
最特殊是k*2+1==n
这种情况就需要打满,不能有余数,我们直接除以(k+1)然后平均分配,剩下的加到y中即可
#include <bits/stdc++.h> #pragma GCC optimize("Ofast") #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <queue> #include <cmath> //#define double long double #define int long long #define endl '\n' using namespace std; const int N=1e6+10,M=1e9; const int INF = 0x3f3f3f3f3f3f3f3f; const int mod=998244353; typedef pair<int,int> PII; void solve() { int n,s,k; cin>>n>>s>>k; if(k==0) { for(int i=1;i<n;i++) { cout<<1<<" "; } cout<<s-n+1<<endl; return; } if(n<=2*k || s<=n+k) { cout<<-1<<endl; return; } if(n==2*k+1) { s-=(2*(k+1)+k); if(s>0 && s<k+1) { cout<<-1<<endl; return; } int t=s%(k+1); int o=1; for(int i=1;i<=n;i++) { if(o==1) { cout<<2+s/(k+1)<<" "; o=0; } else if(o==0) { if(t>0) { cout<<2<<" "; t--; } else cout<<1<<" "; o=1; } } cout<<endl; return; } cout<<2<<" "; for(int i=1;i<=k;i++) cout<<"1 2 "; n=n-(2*k+1); s=s-(2+3*k); if(n!=0) { cout<<s-(n-1)<<" "; } for(int i=1;i<n;i++) { cout<<1<<" "; } cout<<endl; } signed main(){ std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int T=1; cin>>T; while(T--){ solve(); } return 0; }
F-命运的抉择_2024牛客寒假算法基础集训营6 (nowcoder.com)
题解:用并查集维护即可
我们把一个数的倍数全部放在一起
然后我们把这个数包括它的倍数放在b里
剩下的全部放在c里即可
/过程用并查集维护每一个素数即可
#include <bits/stdc++.h> #pragma GCC optimize("Ofast") #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <queue> #include <cmath> //#define double long double #define int long long #define endl '\n' using namespace std; const int N=1e6+10,M=1e9; const int INF = 0x3f3f3f3f3f3f3f3f; const int mod=998244353; typedef pair<int,int> PII; int a[N]; vector<int> b,v; int fa[N]; vector<int> p[N]; int cnt[N]; int find(int x) { if(x==fa[x]) return x; return fa[x]=find(fa[x]); } void an(int x,int y) { x=find(x),y=find(y); fa[x]=y; } void solve() { int n; cin>>n; v.clear(); for(int i=1;i<=n;i++) { fa[i]=i; } for(int i=1;i<=n;i++) { cin>>a[i]; for(auto it:p[a[i]]) { if(!cnt[it]) { cnt[it]=i; v.push_back(it); } else { an(cnt[it],i); } } } for(auto it:v) cnt[it]=0; int f=0; for(int i=1;i<=n;i++) { if(find(i)!=find(4)) f++; } if(!f) { cout<<"-1 -1"<<endl; return; } cout<<n-f<<" "<<f<<endl; for(int i=1;i<=n;i++) { if(find(i)==find(4)) cout<<a[i]<<" "; } cout<<endl; for(int i=1;i<=n;i++) { if(find(i)!=find(4)) cout<<a[i]<<" "; } cout<<endl; } signed main(){ std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int T=1; cin>>T; p[1].push_back(1); for(int i=2;i<N;i++) { if(p[i].size()==0) { for(int j=i;j<N;j+=i) { p[j].push_back(i); } } } while(T--){ solve(); } return 0; }