2025牛客寒假算法基础集训营4
K
小学加减乘除法,取最大值
I
利用后缀数组的思想(前缀也可以)
#include<bits/stdc++.h>
using namespace std;
int n;
string s;
int t;
string x="uwawauwa";
void solve(){
cin>>n;
cin>>s;
int ans=0;
for(int i=0;i<n;++i){
if(s[i]=='u'){
int j=i+1;
if(s[j]=='u')continue;
while(s[j]!='u' && j<n) ++j;
if(j>=n) break;
string y;
for(int k=j;k<=j+7;++k) y+=s[k];
if(x==y) ++ans;
}
}
cout<<ans<<endl;
return ;
}
int main(){
cin>>t;
while(t--){
solve();
}
return 0;
}
E
类似于八皇后问题
利用集合的知识,对于一个位置击败的敌人,应该是两条斜线上的敌人总和-该位置的敌人
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int t;
int n,m;
const int maxn=1e3+10;
map<int,ll>mp1,mp2;
int a[maxn][maxn];
void solve(){
cin>>n>>m;
mp1.clear(),mp2.clear();
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j){
int x;
cin>>x;
a[i][j]=x;
mp1[i+j]+=x;
mp2[i-j]+=x;
}
ll ans=0;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j){
int x=a[i][j];
ans=max(ans,mp1[i+j]+mp2[i-j]-x);
}
cout<<ans<<"\n";
return ;
}
int main(){
cin>>t;
while(t--){
solve();
}
return 0;
}
B
按照题意暴力检验就行
(写的有点shi
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int mod=1e9+7;
int n;
int t;
int ans=0;
string s;
const int maxn=1e3;
bool book[maxn];
int get(){
int p=0,q=0;
for(int i=0;i+1<n;++i){
if(s[i]=='0' && s[i+1]=='1') ++p;
if(s[i]=='1' && s[i+1]=='0') ++q;
}
return p==q?1:0;
}
void check(){//找一个确定的字符串的数量
// cout<<s<<"\n";
for(int i=0;i<n;++i){
s[i]=(s[i]=='1'?'0':'1');
ans+=get();
ans%=mod;
s[i]=(s[i]=='1'?'0':'1');
}
}
void dfs(int x){
int i;
for(i=x+1;i<n;++i){
if(!book[i]) continue;
else break;
}
if(i>=n) check();//字符串已经确定了
else {
s[i]='0';
dfs(i);
s[i]='1';
dfs(i);
}
}
void solve(){
cin>>n;cin>>s;
memset(book,0,sizeof(book));
for(int i=0;i<n;++i) if(s[i]=='?') book[i]=1;
dfs(-1);
cout<<ans%mod<<"\n";
}
int main(){
cin>>t;
while(t--){
ans=0;
solve();
}
return 0;
}
C
按照上题的做法,一定会TLE
因为需要知道一个字符串是否平衡,我们一定要遍历整个字符串,而可能的字符串会有种,
所以我们只能考虑寻找该字符串的性质,以期望快速检验一个字符串是否平衡
- 寻找性质
一个字符串是否平衡取决于01,10的数量是否相等,但是一个一个遍历一定会超时- 首先,我们可以发现,连续的,0,或者,1可以看成一个0,或者1,处理,因为00,11不会对01,10,的数量有影响
- 所以我们拿到一个字符串之后,一定可以化简为 1010101,010101,101010,0101010,这四种情况,只是长度不同
- 这时,我们会发现首尾相同的字符串平衡
性质: 首位相同的字符串平衡
- 分类讨论
我们设总的'?'数量是cnt
同时还要考虑翻转一个字符的字符串的数量
- 首尾都是'?'
1.1首尾相同
,前后不能翻转
1.2首位不同
,不同的有两种情况,翻转后又有两种
2. 头或者尾是'?'
2.1首尾相同
,前后不能翻转
2.2首尾不同
要么翻转头,要么翻转尾巴
- 首尾确定
3.1 首尾相同
3.2 首尾不同
1,2结论相同,合并输出
注意,长度为1时的讨论,看代码你应该懂
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n;
#define ll long long
string s;
int t;
const int mod=1e9+7;
int quick_pow(int a,int b){
if(b<0) return 1;
int cnt=1;
while(b){
if(b&1) cnt=(1ll*cnt*a)%mod;
a=(1ll*a*a)%mod;
b>>=1;
}
return cnt;
}
void solve(){
cin>>n;
cin>>s;
s=" "+s;
if(n==1){
if(s[1]=='?') puts("2");
else puts("1");
return ;
}
int cnt=0;
for(int i=1;i<=n;++i) if(s[i]=='?') ++cnt;
int ans=0;
int y=quick_pow(2,cnt-1)%mod,x=quick_pow(2,cnt)%mod;
if(s[1]!='?' && s[n]!='?'){
if(s[1]==s[n]) ans=1ll*x*(n-2)%mod;
else ans=1ll*x*2%mod;
}
else ans=1ll*y*n%mod;
cout<<ans<<"\n";
return ;
}
int main(){
cin.tie(0);
cout.tie(0);
cin>>t;
while(t--){
solve();
}
return 0;
}
D
可以任意排列,相当于字符可以放在任意位置
很自然地想到,我们可以尽量用短的字符串消除长的字符串中的一些字符
但是一般情况下,短的字符串中会存在一些字符我们无法消除,所以一定我们需要改变a中sum个字符
而在长字符串中
- 如果字符的数量是偶数,那他们可以因为回文串自我消除
- 如果字符的数量是奇数,那他们偶数个字符可以自我消除,剩下的字符一定要自己消除,记为ans
那么其实可以考虑ans的一部分字符去消除sum的字符,也可以用sum的字符消除ans,这取决于两者大小关系
-
,最终答案,
-
,最终答案,
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int t;
void solve(){
string a,b;
map<int,int>mp;
int n,m;
int sum=0,ans=0;
cin>>n>>m>>a>>b;
if(n<m){//确保a是长串
swap(a,b);
swap(n,m);
}
for(int i=0;i<n;++i) mp[a[i]]++;
for(int i=0;i<m;++i)
if(mp[b[i]])mp[b[i]]--;
else sum++;//a中需要改变的字符
for(auto [x,y]:mp)
if(y&1) ++ans;
if(sum>=ans) cout<<sum<<endl;
else cout<<sum+floor((ans-sum)/2)<<endl;
}
int main(){
cin>>t;
while(t--){
solve();
}return 0;
}
F
我谨且做一点总结:
一开始,也觉得似曾相识,我们是否能够直接搜出前k大的数,因为,这里明显既没有性质,也没有算法可以利用
很容易都想到,每个数都要%p,之后根据思路的搜索找到前k大的值
其实我们并没有直接搜索前k大的数,而是搜索最有可能的前k大的数,放入堆中,输出k个值后截止
这里融入了搜索的思想,剪枝,不盲目地搜索,而且保证了搜索所有可能的值
所以这题:我们学到了什么?
在只能暴力的情况下,选择最优雅的暴力
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
typedef pair<int,int> pii;
int n,p,k;
const int maxn=2e5+10;
int t;
int a[maxn];
void solve(){
cin>>n>>p>>k;
for(int i=1;i<=n;++i) cin>>a[i],a[i]%=p;
sort(a+1,a+1+n);
set<pii> sets;
priority_queue<array<int,3>>q;
q.push({(a[n-1]+a[n])%p,n-1,n});
for(int i=n;i>=1;--i){
int j=lower_bound(a,a+i,p-a[i])-a-1;
if(j<1) continue;
q.push({(a[i]+a[j])%p,j,i});
}
while(!q.empty() && k){
auto [val,i,j]=q.top();
q.pop();
if(sets.contains({i,j})) continue;
sets.insert({i,j});
cout<<val<<" ";
k--;
if(i>1) q.push({(a[i-1]+a[j])%p,i-1,j});
if(i<j-1) q.push({(a[i]+a[j-1])%p,i,j-1});
}
while(k--) cout<<-1<<" ";
puts("");
}
int main(){
cin>>t;
while(t--){
solve();
}return 0;
}
A
解释一下
1.因为是等概率随机生成,其实求期望就是:求值/(总的对数)
2.除去总的对数要还要取模,让我想起了逆元,不会的点这里
本文作者:归游
本文链接:https://www.cnblogs.com/guiyou/p/18703000
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步