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
*/