枚举

枚举

1443. 拍照

题目大意:

给定b数组,其中$b_i=a_{i−1}+a_i$

求a数组的可能解中的字典序最小的解

其中a要满足1-n中取值且不能重复

思路:

对每个a[1],都能唯一确定整个a数组

只需要在求a数组的过程中判断每个数是否满足:不重复且范围在1-n

因为要字典序最小,所以在给a[1]赋值的时候从小到大赋值,求到第一个可以的a数组即是答案

代码:

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1010;

int n;
int a[N], b[N];
bool st[N];

bool check(int a1)
{
    memset(st, 0, sizeof st);
    a[1] = a1;
    st[a1] = true;

    for (int i = 2; i <= n; i ++ )
    {
        a[i] = b[i - 1] - a[i - 1];
        if (a[i] < 1 || a[i] > n) return false;
        if (st[a[i]]) return false;

        st[a[i]] = true;
    }

    for (int i = 1; i <= n; i ++ )
        cout << a[i] << ' ';

    return true;
}

int main()
{
    cin >> n;
    for (int i = 1; i < n; i ++ ) cin >> b[i];

    for (int i = 1; i <= n; i ++ )
        if (check(i))
            break;

    return 0;
}

3347. 菊花链

题目大意:

有多少个区间,其中存在整个区间的平均数

思路:

区间内是否存在某个数字:hash set

有时候需要用到快慢指针,本题不需要

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <unordered_set>

using namespace std;

const int N = 110;

int n;
int p[N];

int main()
{
    cin >> n;
    for (int i = 0; i < n; i ++ ) cin >> p[i];

    int res = 0;
    for (int i = 0; i < n; i ++ )
    {
        unordered_set<int> hash;
        for (int j = i, s = 0; j < n; j ++ )
        {
            s += p[j];
            hash.insert(p[j]);
            int cnt = j - i + 1;
            if (s % cnt == 0 && hash.count(s / cnt))
                res ++ ;
        }
    }

    cout << res << endl;
    return 0;
}

1789. 牛为什么过马路 II

题目大意:

给一个长度为52的字符串,26个字母每个出现2次,表示一个环,把相同的字母连线,问有几个字母发生了交叉?

思路:

发生交叉:有且仅有一个字母在两个相同字母中间

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>

using namespace std;

vector<int> p[26];

int main()
{
    string s;
    cin >> s;

    for (int i = 0; i < s.size(); i ++ )
        p[s[i] - 'A'].push_back(i);

    int res = 0;
    for (int i = 0; i < 26; i ++ )
        for (int j = i + 1; j < 26; j ++ )
        {
            int cnt = 0;
            for (auto y: p[j])
                if (p[i][0] < y && y < p[i][1])
                    cnt ++ ;

            if (cnt == 1) res ++ ;
        }

    cout << res << endl;
    return 0;
}

1875. 贝茜的报复

题目大意:

多少种给变量赋值的方法可以使得表达式的计算结果为偶数

思路:

二进制枚举,每位代表一个数

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <unordered_map>

using namespace std;

int main()
{
    int n;
    cin >> n;
    //存储每种字母取奇数和偶数分别有几种情况,例如 cnt[0]['B'] = 3 代表B字母取偶数有3中情况
    unordered_map<char,int> cnt[2];
    while(n --){
        char c;
        int x;
        cin >> c >> x;
        cnt[abs(x) % 2][c] ++;
    }
    
    char str[] = "BESIGOM";
    
    int res = 0;
    //记录在某种情况下某个字母是取奇数还是偶数,例如 v['B'] = 1代表当前情况B取奇数
    unordered_map<char,int> v;
    
    //枚举每一种情况,用一个二进制数来表示 i = 1110000 表示: BES取奇数,IGOM取偶数
    for(int i = 0; i < 1 << 7; i ++){
        //检验i的每一位是0还是1,代表每个字母是取奇数还是偶数
        for(int j = 0; j < 7; j ++){
            v[str[j]] = i >> j & 1;
        }
        
        if((v['B'] + v['I']) * (v['G'] + v['O'] + v['E'] + v['S']) * v['M'] % 2 == 0)
        {
            int sum = 1;
            for(int j = 0; j < 7; j ++){
                sum *= cnt[i >> j & 1][str[j]];
            }
            res += sum;
        }
    }
    cout << res << endl;
    return 0;
}

1855. 愤怒的奶牛

题目大意:

每次爆炸,会引爆周围的草,并使下一次的爆炸半径+1,问能够引爆的干草捆最大数量

思路:

枚举第一次引爆的牛,计算引爆干草的数量

代码:

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 110, INF = 2e9;

int n;
int p[N];

int main()
{
    cin >> n;
    p[0] = -INF, p[n + 1] = INF;
    
    for (int i = 1; i <= n; i ++ )cin >> p[i];
    sort(p + 1, p + n + 1);
    int res = 0;
    for (int i = 1; i <= n; i ++ ){
        //l 代表当前向左爆炸的半径,开始是1,每移动一次a则l + 1,r代表当前向又爆炸的范围
        int l = 1, r = 1, a = i, b = i;
        //当可以进行下一次引爆
        while (p[a] - p[a - 1] <= l)
        {
            //找到下一次可以引爆的最左边的地方
            int k = a - 1;
            //当a能够到k左边一个位置,则将k--
            while (p[a] - p[k - 1] <= l) k -- ;
            a = k;
            l ++ ;
        }
        while (p[b + 1] - p[b] <= r)
        {
            int k = b + 1;
            while (p[k + 1] - p[b] <= r) k ++ ;
            b = k;
            r ++ ;
        }
        res = max(res, b - a + 1);
    }
    cout << res << endl;
    return 0;
}

1826. 农田缩减

题目大意:

二维平面,给了一堆点的坐标,问去掉那个点后,剩下的坐标用矩形框起来,这个矩形面积最小

思路:

枚举每个点被删除,看被删除的点是不是最大值或是最小值,是的话就赋值为次小次大,不是的话就赋值为最小最大

代码:

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 50010;

int n;
int x[N], y[N], a[N], b[N];

int main()
{
    scanf("%d", &n);
    for (int i = 0; i < n; i ++ )
    {
        scanf("%d%d", &x[i], &y[i]);
        a[i] = x[i], b[i] = y[i];
    }

    sort(a, a + n);
    sort(b, b + n);

    int res = 2e9;
    //枚举每个点被删除
    for (int i = 0; i < n; i ++ )
    {
        //分别记录x的最小,最大,y的最小,最大
        int x1, x2, y1, y2;
        //看被删除的点是不是最大值或是最小值
        //是的话就赋值为次小次大,不是的话就赋值为最小最大
        x1 = x[i] == a[0] ? a[1] : a[0];
        x2 = x[i] == a[n - 1] ? a[n - 2] : a[n - 1];
        y1 = y[i] == b[0] ? b[1] : b[0];
        y2 = y[i] == b[n - 1] ? b[n - 2] : b[n - 1];
        res = min(res, (x2 - x1) * (y2 - y1));
    }

    printf("%d\n", res);
    return 0;
}

1913. 公平摄影

题目大意:

两种牛,站成一排,照片中要么只出现一种牛,要么两种牛的数量一样,问照片的尺寸(最左边的牛和最右边的牛的坐标之差)最大是多少

思路:

设两种牛分别是1和-1,则区间[i,j]内两种牛的数量一样等价于该区间的区间和为0,即$S_j - S_{i - 1} = 0$即$S_j=S_{i-1}$

记$S^_i=S_{i-1},则S_j=S^_{i}$,记录每个$S^`_i$第一次出现的位置,当该数值之后再出现的时候,用新的位置减去第一次出现的位置

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <unordered_map>

#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;

const int N = 100010;

int n;
PII q[N];

int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i ++ )
    {
        int x;
        char str[2];
        scanf("%d%s", &x, str);
        if (*str == 'G') q[i] = {x, 1};
        else q[i] = {x, -1};
    }

    sort(q + 1, q + n + 1);

    unordered_map<int, int> hash;

    int res = 0, sum = 0, last;
    for (int i = 1; i <= n; i ++ )
    {
        //记录每个S`i第一次出现的位置(sum没加q[i].y,则sum为S`i)
        if (!hash.count(sum)) hash[sum] = q[i].x;
        sum += q[i].y;
        //如果当前sum以前出现过,则用当前位置减去第一次出现的位置
        if (hash.count(sum)) res = max(res, q[i].x - hash[sum]);

        //计算最长的全是1或-1的区间的长度,如果当前点和上一个点不一样,则当前点是下一个区间的起点
        if (i == 1 || q[i].y != q[i - 1].y) last = q[i].x;
        res = max(res, q[i].x - last);
    }

    printf("%d\n", res);
    return 0;
}

1978. 奶牛过马路

题目大意:

一群牛过马路,第i头牛从ai点走到对面的bi点,问有几头牛的路线和别的牛的路线都没有交叉

思路:

如果第i头牛和别的牛没有交叉,保证:$max(b_1,b_2…b_{i-1}) < b_i$,$min(b_{i+1}…b_n)>b_i$

即:b[i]的前缀最大值小于b[i],b[i]的后缀最小值小于b[i]

代码:

#include <iostream>
#include <cstring>
#include <algorithm>

#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;

const int N = 100010, INF = 1e8;

int n;
PII q[N];
int smax[N], smin[N];

int main()
{
    scanf("%d", &n);

    for (int i = 1; i <= n; i ++ ) scanf("%d%d", &q[i].x, &q[i].y);

    sort(q + 1, q + n + 1);

    smax[0] = -INF, smin[n + 1] = INF;
    for (int i = 1; i <= n; i ++ ) smax[i] = max(smax[i - 1], q[i].y);
    for (int i = n; i; i -- ) smin[i] = min(smin[i + 1], q[i].y);

    int res = 0;
    for (int i = 1; i <= n; i ++ )
        if (smax[i - 1] < q[i].y && smin[i + 1] > q[i].y)
            res ++ ;

    printf("%d\n", res);
    return 0;
}

1969. 品种邻近

题目大意:

一排牛,每只牛有一个品种ID。

如果两头牛的品种ID相同,且距离小于k,则这叫一个拥挤奶牛对

问拥挤奶牛对中品种ID最大的是多少。

思路:

判断某个ID在之前出现的位置:

法一:用一个map存储每个id最后出现的位置

法二:将当前牛的前k个位置放入一个队列中,并用一个数组记录队列中的每个元素出现的次数,若当前牛的品种ID出现在队列中,则这是一个拥挤奶牛对

代码:

法一:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>

using namespace std;

const int M = 1000010;

int cnt[M];
map<int,int> m;

int main()
{
    int n;
    int k;
    cin >> n >> k;
    int res = -1;
    for(int i = 0; i < n; i ++){
        int id;
        cin >> id;
        if(m.count(id)){
            if(i - m[id] <= k)res = max(res, id);
        }
        m[id] = i;
    }
    cout << res << endl;
    return 0;
}

法二:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;

const int M = 1000010;

int cnt[M];
queue<int> q;

int main()
{
    int n;
    int k;
    cin >> n >> k;
    int res = -1;
    for(int i = 0; i < n; i ++){
        int id;
        cin >> id;
        if(cnt[id])res = max(res, id);
        q.push(id);
        cnt[id] ++;
        if(q.size() > k){
            cnt[q.front()] --;
            q.pop();
        }
        
    }
    cout << res << endl;
    return 0;
}

1960. 闪烁

题目大意:

农夫约翰对牛棚里昏暗的灯光感到不满,刚刚安装了一个新吊灯。

新吊灯由 N 个灯泡组成,这 N 个灯泡围成一圈,编号为 0∼N−1。

奶牛对这个新吊灯非常着迷,并且喜欢玩以下游戏:

对于第 i 个灯泡,如果在 T−1 时刻,它左侧的灯泡(当 i>0 时,为第 i−1个灯泡;当 i=0 时,为第 N−1 个灯泡)是开着,那么在 T 时刻,就切换这个灯泡的状态。

这个游戏将持续 B 单位时间。

给定灯泡的初始状态,请确定在 B 单位时间后,它们的最终状态。

思路:

用一个数state的每一位表示某个灯的亮灭

记录从当前到每个state的走的步数

如果走到了之前走到的state,则说明走到了环的入口

代码:

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;

const int N = 1 << 16;

int n;
LL m;
//p数组表示某一种状态从原点走几步走到
int p[N];

int update(int state){
    int res = 0;
    for(int i = 0; i < n;i ++){
        int j = (i - 1 + n) % n;
        //x是原来的第i位,y是原来的第i - 1位
        int x = state >> i & 1, y = state >> j & 1;
        //如果y是1,则把新的状态(res)的第i位置为与x相反
        if(y) {
            if(x) res |= 0 << i;
            else res |= 1 << i;
        }
        //否则,res的第i位即x
        else{
            res |= x << i;
        }
        // res |= (x ^ y) << i;
        // 等价于 res |= (x ^ y) << i;
    }
    return res;
}

void print(int state)
{
    for (int i = 0; i < n; i ++ )
        cout << (state >> i & 1) << endl;
}
int main()
{
    cin >> n >> m;
    //state的二进制表示形式表示每一位的灯是亮还是灭
    int state = 0;
    //逐位设置每个灯是亮还是灭
    for(int i = 0; i < n; i ++){
        int x;
        cin >> x;
        state |= x << i;
    }
    
    memset(p, -1, sizeof(p));
    p[state] = 0;
    for(int i = 1;;i ++){
        //update函数返回接下来一步的状态
        state = update(state);
    
        //走到了最后一步,则输出
        if(i == m){
            print(state);
            break;
        }
        //新的一步在之前没走过,则记录从源点走到该状态所需的步数i,p[state] = i;
        else if(p[state] == -1)p[state] = i;
        //新的一步在之前出现过,说明走到了循环的入口,state即循环入口的状态
        else{
            //循环的长度,即当前的步数减去从源点走到循环入口的长度
            int len = i - p[state];
            int r = (m - i) % len;
            while(r --)state = update(state);
            print(state);
            break;
        }
    }
    return 0;
}

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 1149440709@qq.com

×

喜欢就点赞,疼爱就打赏