为了能到远方,脚下的每一步都不能少.|

园龄:粉丝:关注:

蓝桥杯集训·题解 week 1

农夫约翰的奶酪块

抽取一个方块之后,记录对于其所在行,列,竖的数量加+1

如果有行,列,竖的数量达到了n,则说明可以插入一个1*n的块
所以对答案贡献加+1

而我们注意到同一行的,列,竖坐标相同。相同的列,竖以此类推

点击查看代码
#include<bits/stdc++.h>

using namespace std;

typedef pair<int,int> pii;
int t;
int n,q;
map<pii,int>mp1,mp2,mp3;
void solve(){
    cin>>n>>q;
    int ans=0;
    for(int i=1;i<=q;++i){
        int x,y,z;
        cin>>x>>y>>z;
        mp1[{x,y}]++;
        mp2[{y,z}]++;
        mp3[{x,z}]++;
        if(mp1[{x,y}]==n) ++ans;
        if(mp2[{y,z}]==n) ++ans;
        if(mp3[{x,z}]==n) ++ans;
        cout<<ans<<endl;
    }    return ;
}


int main(){
    t=1;
    while(t--){
        solve();
    }
    return 0;
}

哞叫时间

(写的有点shi)
不过核心思路是,枚举字符串里面每一个字符,然后将其改变成其他字符,最后统计改变,满足条件的字符串是否增加
因为改变一个字符,只会最多改变三个长度为3的字符串

点击查看代码
#include<bits/stdc++.h>

using namespace std;

map<string,int>mp;
int n,f;
string s;
int main(){
    cin>>n>>f;
    cin>>s;
    set<string> cnt;
    for(int i=0;i<n-2;++i){
        string t;
        if(s[i+1]==s[i+2] && s[i]!=s[i+1]){
            t=s[i];t+=s[i+1];t+=s[i+2];
            mp[t]++;
            if(mp[t]>=f) cnt.insert(t);
        //    cout<<t<<endl;
        }
    }

    for(int i=0;i<n;++i){
        string ta,tb,tc,sa,sb,sc;
        if(i>1){
            if(s[i]==s[i-1]){
                sa=s[i-2];sa+=s[i-1];sa+=s[i];
                mp[sa]--;
            }
        }
        if(i>0){
            if(s[i]==s[i+1]){
                sb=s[i-1];sb+=s[i];sb+=s[i+1];
                mp[sb]--;
            }
        }if(i<n-2){
        	if(s[i+1]==s[i+2]){
        		sc=s[i];sc+=s[i+1];sc+=s[i+2];
            	mp[sc]--;
			}
        }
        
        for(int j=0;j<=25;++j){
            char c='a'+j;
            if(c==s[i]) continue;
            if(i>1 && c==s[i-1]){
                ta=s[i-2];ta+=s[i-1];ta+=c;
                if(mp[ta]+1>=f) cnt.insert(ta);
            }
            if(i>0 && c==s[i+1]){
                tb=s[i-1];tb+=c;tb+=s[i+1];
                if(mp[tb]+1>=f) cnt.insert(tb);
            }
            if(i<n-2 && s[i+1]==s[i+2]){
                tc=c;tc+=s[i+1];tc+=s[i+2];
                if(mp[tc]+1>=f) cnt.insert(tc);
            }
        }
        if(i>1){
            if(s[i]==s[i-1])
                mp[sa]++;
        }
        if(i>0){
            if(s[i]==s[i+1])
                mp[sb]++;
        }if(s[i+1]==s[i+2] && i<n-2){
        		sc=s[i];sc+=s[i+1];sc+=s[i+2];
            	mp[sc]++;
		}
	}
    cout<<cnt.size()<<"\n";
    for(auto i:cnt){
        cout<<i<<"\n";
    }
    return 0;
}

蛋糕游戏

思维题

这道题应该是摸清题意,左右选择最大的,选取的方式是固定,但是合并的操作是要思考的,怎么合并能更大
长度为偶数
由于左右选择是第二步,所以,最后剩下两个时,合并后会吃掉,所以合并可以吃最多n/2+1个,左右吃是n/2-1个

无论如何左右选择,它吃的数量至少是n/2-1个,所以合并为了吃的蛋糕最多,一定要尽量吃n/2+1个

所以构建如下策略

a b c d e f g h
1.合并d,e
a b c {d e} f g h
2.吃掉max(a,h),假设h大
a b c {d e} f g {h}

1.合并d,e
a {b c d e} f g {h}

2.吃掉max(a,g),假设a大
{a} {b c d e} f g {h}

1.合并d,e

此时完成

由上我们可以发现,我们首先合并最中间的两个,当吃的选择一个方向之后,我们选择合并另一个方向靠近中间的两个
这样操作之后,合并的一定能吃够它吃的数量n/2+1个,达到最优解

点击查看代码

#include<bits/stdc++.h>

using namespace std;
#define ll long long 
int t;
int n;
const int maxn=5e5+10;
ll sum[maxn];
int a[maxn];
ll cnt=1e15;
void solve(){
    cin>>n;
    sum[0]=0;cnt=1e15;
    for(int i=1;i<=n;++i) cin>>a[i],sum[i]=sum[i-1]+a[i];
    
    for(int i=1;i+n/2<=n;++i){
        cnt=min(cnt,sum[i+n/2]-sum[i-1]);
    }
    cout<<cnt<<" "<<sum[n]-cnt<<endl;
    return ;
}
int main(){
    cin>>t;
    while(t--){
        solve();
    }
    return 0;
}

哞叫时间II

找到一个长度为3的子数组满足后两个相等,第一个与后两个相等

所以,如果我们确定了一个子数组的第二个数,我们就可以任取,该数之前的所有不与其相等的数,就可以与他形成一个子数组

所以我们从后往前枚举,找到一个出现过两次的数,并记录他的位置

然后从前往后找,我们记录出现过不同的数的数量,如果遇到出现过两个数的位置,那么对答案产生贡献,注意如果在这之前还出现过该数,需要-1

点击查看代码
#include<bits/stdc++.h>

using namespace std;
#define ll long long 
int n;
const int maxn=1e6+10;
int a[maxn];
int mp[maxn];
bool book[maxn];
ll ans=0;

ll cnt=0;

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;++i) cin>>a[i];
    for(int i=n;i>=1;--i){
        if(mp[a[i]]==0) mp[a[i]]=-1;
        else if(mp[a[i]]==-1){
            mp[a[i]]=i;
        }
    }
    for(int i=1;i<n;++i){
        if(mp[a[i]]==i){
            ans+=cnt+(book[a[i]]?-1:0);
        }
        if(book[a[i]]) continue;
        book[a[i]]=1;
        ++cnt;
    }
    cout<<ans<<endl;
    return 0;
}

奶牛体检

纯粹的暴力,一定会超时

我们考虑一种翻转方式,如果翻转了(i,j),那我们再去翻转(i-1,j+1),那么此时只用考虑i-1和j+1的位置交换后是否能够匹配

所以这样就避免了,翻转过的再翻转,降低了时间复杂度

具体实现:

如果一个区间是奇数长度,我们从i点扩展成(i-1,i+1)
如果一个区间是偶数长度,我们从(i,i+1)点扩展成(i-1,i+2)

此题给了我们暴力枚举所有的(i,j)数对,优化的暴力枚举方法

这样的枚举方法,能够更有效地统计对答案的贡献

点击查看代码
#include<bits/stdc++.h>

using namespace std;
#define ll long long 
int n;
const int maxn=1e6+10;
ll cnt=0;
int a[maxn],b[maxn];
ll ans[maxn];

int main(){
    cin>>n;
    for(int i=1;i<=n;++i) cin>>a[i];
    for(int i=1;i<=n;++i){
        cin>>b[i];
        if(a[i]==b[i]) ++cnt;
        
    }
    for(int i=1;i<=n;++i)
        for(int j=0;j<=1;++j){
            ll sum=cnt;
            for(int l=i,r=i+j;l>=1 && r<=n;++r,--l){
                if(a[l]==b[l]) --sum;
                if(a[r]==b[r]) --sum;
                if(a[l]==b[r]) ++sum;
                if(a[r]==b[l]) ++sum;
                ans[sum]++;
            }
            
        }
    for(int i=0;i<=n;++i) cout<<ans[i]<<"\n";
}

本文作者:归游

本文链接:https://www.cnblogs.com/guiyou/p/18739567

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @ 2025-02-26 21:38  归游  阅读(5)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起