周测题解9.3

Information Onceaweek Inzhizhen boomed again and again

T1

经典数论几何题。

一个最基本的贪心策略就是先横向摆(此时还剩一个 n×(nmodm)的空)。

然后再在空里竖着摆(此时剩 (nmodm)2 的空),就摆不下了。

因为OI不用证明贪心这个贪心是最优的,答案就是 (nmodm)2

T2

懒得再写一遍了,这篇的T4就是。

T3

队列应用题。(虽然我考场上没写出来

首先先说一点,枚举区间是不可避免的。

但枚举区间不一定要用 O(n2) 的大暴力。

这里就需要动态维护(不知道用词对不对)两个端点。

那么我们就可以用到队列了。

思路

首先,肯定是依次往队里压,每次压完判断一下队里的是否可以作为答案。

这就是第一个难点了:怎么判断队里的东西可不可以作为答案呢?

我们需要知道,这题的目的是去掉(替换)该去掉的点

那么该去掉的点有几个呢?

我们知道,每个点都要剩下 n/4 个。

那么用原有点数 - 应该剩下的点数就是该去掉的点数了。

即对于字符 ccount(c)n/4=c 该去掉的点数。(其中 count 是统计 s 中 c 的个数)。

判断完了队中元素是否可以作为答案,那怎么维护左端点呢?

这又是另一个难点了:

我们知道,这个区间是越短越好的。

所以队头只要每压一次就一直弹出,就可以保证区间最小。

然而肯定不能一直弹,我们就可以想到:

一直弹到不能弹为止。(不可以作为答案)

代码

#include <iostream>
#include <queue>
#include <unordered_map>
#include <string>
#include <algorithm>
using namespace std;
unordered_map<char, int> nd, iq;int n, ans = 1e9;string s;queue<char> q;
bool chk()
{
    for(char i = 'A';i <= 'D';++i)
        if(iq[i] < nd[i]) return 0;
    return 1;
}
int main()
{
    cin >> n >> s;
    for(char i = 'A';i <= 'D';++i)
        nd[i] = count(s.begin(), s.end(), i) - n / 4;
    for(int i = 0;i < n;++i)
    {
        q.push(s[i]);++iq[s[i]];
        while(chk())
        {
            ans = min(ans, int(q.size()));
            --iq[q.front()];q.pop();
        }
    }
    cout << ans;
    return 0;
}
posted @   Jijidawang  阅读(3)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示