CF780

A

题意:

你有\(a\)个一块钢镚和\(b\)个两块钢镚,求你不能恰好支付的最小钱数。

\(a,b\leq 10^18,T\leq 10^4\)

题解:

如果没有一块钢镚,输出\(1\)

否则输出\(2*b+a+1\)

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define double long double
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define lowbit(i) ((i)&(-i))
#define mid ((l+r)>>1)
#define eps (1e-8)
    const int N=2e5+10,mod=998244353,inf=2e9;
    int n;
    inline void main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);cout.tie(0);
        int T;cin>>T;
        while(T--)
        {
            int a,b;
            cin>>a>>b;
            if(a==0)
            {
                cout<<1<<'\n';
            }
            else
            {
                cout<<2*b+a+1<<'\n';
            }
        }
    }
}
signed main()
{
    red::main();
    return 0;   
}
/*
1
1 2 3 4

*/

B

题意:

你有\(n\)种不同的糖,每种有\(a_i\)个。

你不会连吃两块一样的糖,你想知道能不能把糖吃完。

\(n\leq 2*10^5,a_i\leq 10^9\)

题解:

先排序,特判\(n=1\)

然后如果\(a_n>a_{n-1}+1\)就不行。

否则就可以交替吃糖吃完。

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define double long double
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define lowbit(i) ((i)&(-i))
#define mid ((l+r)>>1)
#define eps (1e-8)
    const int N=2e5+10,mod=998244353,inf=2e9;
    int n,sum;
    int a[N];
    inline void main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);cout.tie(0);
        int T;cin>>T;
        while(T--)
        {
            cin>>n;sum=0;
            for(int i=1;i<=n;++i)
            {
                cin>>a[i];
            }
            bool flag=1;
            sort(a+1,a+n+1);
            if(n==1)
            {
                if(a[1]==1) cout<<"YES\n";
                else cout<<"NO\n";
                continue;
            }
            if(a[n]>a[n-1]+1) flag=0;
            if(flag) cout<<"YES\n";
            else cout<<"NO\n";
        }
    }
}
signed main()
{
    red::main();
    return 0;   
}
/*
1
1 2 3 4

*/

C

题意:

一个字符串是均匀的,当且仅当它的长度是偶数,而且对于任意奇数位置\(i\),满足\(s[i]==s[i+1]\)

给定一个字符串,问最少删除多少个字符让这个字符串变得均匀,字符都是小写字母。

\(|s|\leq 2*10^5\)

题解:

考虑设\(dp[i]\)是到\(i\)为止,\(1\sim i\)被调教均匀需要的最少删除次数。

首先可以让\(i\)个字符暴毙,有\(dp[i]=dp[i-1]+1\)

设第\(i\)个字符之前最近跟它一样的字符位置是\(pre\),那么可以让他俩配对,然后中间的字符都删了\(dp[i]=min(dp[i],dp[pre-1]+(i-pre-1))\)

最后答案就是\(dp[n]\)

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define double long double
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define lowbit(i) ((i)&(-i))
#define mid ((l+r)>>1)
#define eps (1e-8)
    const int N=2e5+10,mod=998244353,inf=2e9;
    int n,minn,ans;
    char s[N];
    int dp[N];
    int pre[N];
    inline void main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);cout.tie(0);
        int T;cin>>T;
        while(T--)
        {
            cin>>(s+1);ans=inf;
            n=strlen(s+1);
            for(int i=0;i<26;++i) pre[i]=0;
            for(int i=1;i<=n;++i)
            {
                int t=s[i]-'a';
                dp[i]=dp[i-1]+1;
                if(pre[t]) dp[i]=min(dp[i],dp[pre[t]-1]+(i-pre[t]-1));
                ans=min(ans,dp[i]+n-i);
                pre[t]=i;
            }
            cout<<dp[n]<<'\n';
            //cout<<ans<<'\n';
        }
    }
}
signed main()
{
    red::main();
    return 0;   
}
/*
1
1 2 3 4

*/

D

题意:

有一个\(n\)个数的数组,你可以从前面和后面删除连续的任意个数字,问应该从前面删多少个连续的,再从后面删多少个连续的,让剩下的数字乘积可以最大?空数组大小是\(1\)

\(n\leq 2*10^5,-2\leq a_i\leq 2\)

题解:

就先保证不是\(0\),大不了把整数数组全删了变成\(1\),所以对每一段没有\(0\)的段单独考虑。

对于某一段,先保证不是负数,但是这个不是负数有讲究的,如果是负数,就从左和右往里找到第一个负数,然后去掉\(|a_i|=2\)比较少的那一边。最后算一下\(2\)的数量\(cnt\),这一段的大小就是\(2^{cnt}\)

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define double long double
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define lowbit(i) ((i)&(-i))
#define mid ((l+r)>>1)
#define eps (1e-8)
    const int N=2e5+10,mod=998244353,inf=2e9;
    int n,ql,qr,ans;
    int pre;
    int a[N];
    inline void work(int l,int r)
    {
        if(l>r) return;
        int sum=0,s2=0;
        for(int i=l;i<=r;++i)
        {
            if(a[i]<0) ++sum;
            if(abs(a[i])==2) ++s2;
        }
        if(sum%2==0)
        {
            if(s2>ans) ans=s2,ql=l-1,qr=n-r;
            return;
        }
        int tl=l-1,tr=r+1;
        int s=0,ss=0;
        while(1)
        {
            ++tl;
            s+=(abs(a[tl])==2);
            if(a[tl]<0) break;
        }
        while(1)
        {
            --tr;
            ss+=(abs(a[tr])==2);
            if(a[tr]<0) break;
        }
        if(s<ss) l=tl+1,s2-=s;
        else r=tr-1,s2-=ss;
        if(s2>ans) ans=s2,ql=l-1,qr=n-r;
    }
    inline void main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);cout.tie(0);
        int T;cin>>T;
        while(T--)
        {
            cin>>n;
            pre=1;ans=0;
            ql=n;qr=0;
            for(int i=1;i<=n;++i)
            {
                cin>>a[i];
                if(a[i]==0)
                {
                    work(pre,i-1);
                    pre=i+1;
                }
            }
            work(pre,n);
            cout<<ql<<' '<<qr<<'\n';
        }
    }
}
signed main()
{
    red::main();
    return 0;   
}
/*
1
1 2 3 4

*/

E

题意:

给一个\(n*n\)的格子,每个位置上是\(1\)\(0\)

你可以把所有行循环上移,或者循环左移任意次。

然后你要取反一些格子上的状态,让矩阵除了主对角线上是\(1\),其他位置都是\(0\)

问最少要取反多少个格子?

\(n\leq 2000\)

题解:

比赛时候乱想。。

枚举第一行的哪个位置作为起点,然后可以\(O(n)\)确定主对角线上一开始有多少个\(1\)

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define double long double
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define lowbit(i) ((i)&(-i))
#define mid ((l+r)>>1)
#define eps (1e-8)
    const int N=2000+10,mod=998244353,inf=2e9;
    int n,tot,ans;
    char s[N][N];
    int d[N*2][N*2];
    inline int work(int x,int y)
    {
        int tmp=min(n-x,n-y);
        int sum=d[x+tmp][y+tmp]-d[x-1][y-1];
        int tx=x+tmp+1,ty=y+tmp+1;
        if(tx>n) tx=1;
        if(ty>n) ty=1;
        tmp=n-tmp-2;
        sum+=d[tx+tmp][ty+tmp]-d[tx-1][ty-1];
        return (n-sum)+(tot-sum);
    }
    inline void main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);cout.tie(0);
        int T;cin>>T;
        while(T--)
        {   
            cin>>n;tot=0;ans=n*n;
            for(int i=0;i<=n+1;++i)
                for(int j=0;j<=n+1;++j) d[i][j]=0;
            for(int i=1;i<=n;++i)
            {
                cin>>(s[i]+1);
                for(int j=1;j<=n;++j)
                {
                    tot+=(s[i][j]=='1');
                    d[i][j]=d[i-1][j-1]+(s[i][j]=='1');
                }
            }
            for(int i=1;i<=n;++i)
            {
                for(int j=1;j<=n;++j)
                {
                    ans=min(ans,work(i,j));
                }
            }
            cout<<ans<<'\n';
        }
    }
}
signed main()
{
    red::main();
    return 0;   
}
/*
1
3
100
101
000

*/

F1

题意:

给定一个字符串\(s\),仅由\(+\)\(-\)构成。

如果字符串是平衡的,那么应该包含相同数量的加号和减号。

你可以进行以下操作:把两个相邻的减号换成一个加号。

如果一个字符串可以通过任意次操作变成平衡的,那这个字符串是有希望的。

\(s\)有多少个非空子串是有希望的?

\(|s|\leq 3000\)

考虑枚举右端点\(r\),然后从右向左枚举左端点\(l\),顺便记录一些信息。

\(s1\)表示区间有多少个\(+\)

\(s2\)表示区间有多少个\(-\)

\(s3\)表示区间最多有多少个\(--\),注意这里一个\(-\)不能用两次。

如果某段区间满足\(s1\leq s2\),并且\((s2-s1)\%3==0\),那么这个区间是满足要求的。

因为一次操作可以把两个\(s2\)换成一个\(s1\),也就是说\(s2\)\(s1\)再怎么操作,模\(3\)都同余。

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define double long double
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define lowbit(i) ((i)&(-i))
#define eps (1e-8)
    const int N=2e5+10,mod=998244353,inf=2e9;
    int n,sum;
    char s[N];
    int a[N];
    inline void main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);cout.tie(0);
        int T;cin>>T;
        while(T--)
        {
            cin>>n;sum=0;
            cin>>(s+1);
            for(int r=1;r<=n;++r)
            {
                for(int i=1;i<=r;++i) a[i]=(s[i]=='+');
                int s1=0,s2=0,s3=0;
                for(int l=r;l>=1;--l)
                {
                    if(a[l]) ++s1;
                    else ++s2;
                    if(a[l]==0&&a[l+1]==0&&l+1<=r)
                    {
                        ++s3;
                        a[l]=a[l+1]=1;
                    }
                    if(s1<=s2&&(s2-s1)%3==0) ++sum;
                }
                //cout<<sum<<"!!"<<endl;
            }
            cout<<sum<<'\n';
        }
    }
}
signed main()
{
    red::main();
    return 0;   
}
/*
1
1 2 3 4

*/

F2

\(n\leq 2*10^5\)

后面这个总结的判断条件看上去就很能被数据结构给优化掉。

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define double long double
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define lowbit(i) ((i)&(-i))
#define mid ((l+r)>>1)
#define eps (1e-8)
    const int N=2e5+10,mod=998244353,inf=2e9;
    int n,ans;
    char s[N];
    int tr[N<<2][3];
    inline void update(int x,int k,int id)
    {
        for(int i=x;i<=2*n+1;i+=lowbit(i)) tr[i][id]+=k;
    }
    inline int query(int x,int id)
    {
        int sum=0;
        for(int i=x;i;i-=lowbit(i)) sum+=tr[i][id];
        return sum;
    }
    inline void main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);cout.tie(0);
        int T;cin>>T;
        while(T--)
        {
            cin>>n;ans=0;
            cin>>(s+1);
            for(int i=1;i<=2*n+1;++i) tr[i][0]=tr[i][1]=tr[i][2]=0;
            update(n+1,1,0);
            int sum=0;
            for(int i=1;i<=n;++i)
            {
                sum+=(s[i]=='+'?1:-1);
                int b=(sum%3+3)%3;
                ans+=query(2*n+1,b)-query(sum+n,b);
                update(sum+n+1,1,b);
            }
            cout<<ans<<'\n';
        }
    }
}
signed main()
{
    red::main();
    return 0;   
}
/*
1
1 2 3 4

*/
posted @ 2022-04-11 22:07  lovelyred  阅读(39)  评论(0)    收藏  举报