CodeForces - 1248D1 (思惟+暴力)

題意

有一個括號序列,你能夠選擇兩個位置i,j(i能夠等於j),進行交換。使得最後的循環位置(i的數目)最大。ios

循環位置:i(0<=i<len),將前i個字符移到最後,獲得的新序列是合法的括號序列。c++

  • )()()( 的循環位置有 一、三、5
  • )((()))( 的循環位置有 一、7

思路

這題還有個大數據範圍版本,那題思路太神仙了,我等凡人就學學暴力吧!這題有個結論,假設)爲-1,(爲+1,那麼一個括號序列的循環匹配個數等於前綴和最小值的個數。證實參考某大佬的:大數據

假設對於序列)()(,它的前綴和是-1 0 -1 0spa

當上述前綴值<0時,這個前綴序列必定是不合法的。而後考慮何時把括號序列的一段前綴移到後面去是合法的。code

首先你須要使得移動以後,前面的括號序列合法。也就是說你得把一段「連續的極長非合法前綴」找出來(對於樣例是))。這個東西剛好在前綴和第一次取得最小值時取得(前綴和取-1)。而後實際上你還能夠在這個前綴後面接上一些「自己合法」的括號序列,像這樣:)()。後面那個合法的序列對答案沒有影響,所以循環移位的數量就是前綴和最小值的數量。blog

而後咱們就能夠O(n^3)暴力啦!ci

代碼

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define ll long long
const int N=200005;
const int mod=1e9+7;
const double eps=1e-8;
const double PI = acos(-1.0);
#define lowbit(x) (x&(-x))
int n;
string s;
int solve()
{
    int sum=0,mi=0,cnt=0;
    for(int i=0; i<n; i++)
    {
        if(s[i]=='(')
            cnt++;
        else
            cnt--;
        mi=min(cnt,mi);
    }
    cnt=0;
    for(int i=0;i<n;i++)
    {
        if(s[i]=='(')
            cnt++;
        else
            cnt--;
        if(cnt==mi)
            sum++;
    }
    return sum;
}
int main()
{
    std::ios::sync_with_stdio(false);
    cin>>n>>s;
    int cnt=0;
    for(int i=0; i<n; i++)
    {
        if(s[i]=='(')
            cnt++;
        else
            cnt--;
    }
    if(cnt)
    {
        cout<<"0\n1 1"<<endl;
        return 0;
    }
    int ans=solve();
    int l=1,r=1;
    for(int i=0;i<n;i++)
    {
        for(int j=i+1;j<n;j++)
        {
            swap(s[i],s[j]);
            int tmp=solve();
            if(tmp>ans)
            {
                l=i,r=j;
                ans=tmp;
            }
            swap(s[i],s[j]);
        }
    }
    cout<<ans<<endl;
    cout<<l+1<<" "<<r+1<<endl;
    return 0;
}
相關文章
相關標籤/搜索