C题使用双指针+dp (不知道这样是否为正解特此求各位大佬审批)

#include<bits/stdc++.h>

#include<climits>

#define all(x) x.begin(),x.end()

#define pb(x) push_back(x)

#define i64 long long

#define fi first

#define se second

#define endl '\n'

#define mod3 998244353

#define mod7 1000000007

#define de(x) cerr << #x <<" "<<x <<" ";

#define deb(x) cerr << #x <<" "<<x <<endl;

using namespace std;

using pii = pair<int,int>;

using pll = pair<i64, i64>;

// 2025.07.11——19:23:03

/* 相当于向前移动k - 1位置 => 改动为向后以为就应该是

 * 向后移动n-k+1 位

 * [1 , 2, 3] => k = 2 [2, 3] + [1] <==> [] 移动两位

 * n = 3, k = 2  就是 n - k + 1 位置

//  * 时间复杂度为 第一个数字的个数 * m * log(当前选中的数字的个数的两倍)

 * 将每个数字的下标存在一个二维数组中 二分判断

 * 超时TLE

 * 其中我们可以发现一个性质就是、其一段数字内能增加解集的部分就是有一段

 * 重复的个数,但是是0的重复的个数才可以增加

 *

 * 双指针去做,因为当我判定了一段区间是没有解的情况下,

 * 我就会发现这一段区间无论如何都是不可能有解的,

 *

 * 如果我找到一个解的话,我只需要判断最前面0的个数就可以进行知道有多少个解集

 * 外循环循环最初开始的位置i 找0

 * 中间判断现在是否是有解的,

 * 如何判断有解,只需要存储现在的最小值mi即可

 * 如果出现了大于mi + 1 的值则无解直接跳过

 * 如果出现 mi+1 则将最小值更迭,

 * 还需要一个值来存储前缀0的个数也就是最终的答案数cnt0

 * 而其中 mi 只要到达了 m - 1即可 得出该区段解;

 * 然后寻找下一个 0的位置

 *

 *

 * 需要在双指针内部存在可加可减的数据结构

*/

void solve(){

    i64 m, n;

    cin >> n >> m;

    vector<i64>a(2 * n);

    for (int i = 1;i <= n;i++) {

        cin >> a[i];

        if(i!=n)a[i + n] = a[i];

    }

    // for (int i = 1;i <= 2 * n;i++) {

    //     cout << a[i] << " ";

    // }cout << endl;

    i64 i = 1, ans = 0;

    set<i64>st;

    while (i <= n) {

        // deb(i)

        vector<i64>dp(m, 0);

        i64 mi = 0;

        while (a[i] != 0 && i <= n) { i++; }

        if (i > n )break;

        i64 j = i;

        while (i + n > j && j <= n && a[j] == 0) {

            dp[0]++;

            j++;

        }

        while ( i + n > j && j <= 2*n && mi + 1 >= a[j] && mi < m - 1LL) {

            if (a[j] == 0) {

                if(j <= n)dp[0]++;

                st.insert(a[j]);

            } else {

                dp[a[j]] += dp[a[j] - 1];

                dp[a[j] - 1] = 0;

                st.erase(a[j] - 1);

                st.insert(a[j]);

                vector<i64>s;

                for (auto x: st) {

                    if (x < a[j]) {

                        s.pb(x);

                    } else { break; }

                }

                for (auto x : s) {

                    st.erase(x);

                    dp[x] = 0;

                }

            }

            mi = max(mi, a[j]);

            j++;

            // for (int i = 0;i < m;i++) {

            //     cout << dp[i] << " ";

            // }cout << endl;

        }

        if (mi == m - 1LL) {

            ans += dp[m-1];

        }

        i = j;

        // cout << endl;

    }

    cout << ans << endl;

}

// 2025.07.11——20:08:40 wa eeee......

/* 错误的样例

7 4

0 1 2 0 1 2 3

0 : 0

1 : 0

2 : 1

i = 3

0 : 1

i = 4

*/

// 2025.07.11——20:13:42 TLE 。。。

// 2025.07.11——20:33:52 双指针 + dp错了斯

// 2025.07.12——01:43:27

/* 错误样例 错误点在于当下标值大于n的时候还计算了最后的解集

10 2

0 1 1 0 1 1 0 1 0 0

*/

int main() {

    ios_base::sync_with_stdio(false);

    cin.tie(nullptr);

    cout.tie(nullptr);

    int T = 1;

    //cin >> T;

    while(T--){

        solve();

    }

    return 0;

}

全部评论

相关推荐

吴offer选手:下午mt一来就告警说项目来不及,估计明天拿了权限就要参与开发了 已老实
实习生的蛐蛐区
点赞 评论 收藏
分享
嵐jlu:我是山川🐔里🐔🧱的,阿里系简历全过; 你这简历一看就还是半成品啊,没有荣誉经历奖项什么的吗?
投递阿里巴巴集团等公司8个岗位
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务