Codeforces Round #780 (Div. 3) A-F2题解
Codeforces Round #780 (Div. 3)
A
题意
给定\(a\)个价值一块钱的硬币,\(b\)个价值为两块钱的硬币,问:最小的不能买的商品价值。
数据范围
思路
如果\(a=0\),那么所有奇数价值的商品都不能买,否则就可以买\(a+2*b\)以下的所有商品。
代码
int a,b;
void solve() {
cin>>a>>b;
if(a==0)cout<<1<<"\n";
else cout<<a+b*2+1<<"\n";
}
B
题意
给定\(n\)种糖果的数量,每次可以吃出现频率最高的一种糖果,前后两次吃的糖果不能是同一类糖果。
数据范围
思路
考虑数量最多的两种糖果数量,如果第二高的糖果数量-第一高的数量\(>1\),那么显然不行。
代码
这个代码写的太复杂了,赛时一开始读错题了。
int n;
int maxn=0;
map<int,int>mp;
void solve() {
cin>>n;
maxn=0;
mp.clear();
for(int i=1;i<=n;i++){
int tmp;cin>>tmp;
mp[tmp]++;
maxn=max(maxn,tmp);
}
if(maxn==1||mp[maxn]>=2){
cout<<"YES\n";
return ;
}
if(!mp[maxn-1]){
cout<<"NO\n";
return;
}
cout<<"YES\n";
}
C
题意
如果一个字符串满足以下两个条件,那么我们称它为美丽字符串:
- 这个字符串的长度为偶数。
- 对于每个奇数位的字符来说,\(a_i=a_{i+1}\)
问:给定一个字符串,问最少删几个字符,使剩下的字符串为美丽字符串。
数据范围
思路
for一遍,如果当前的子串中有出现了两个一样的字符了,那么直接清空数组,可以保留的字符数量+=2,最后的答案就是原字符串长度-可以保留的字符数量。
代码
string s;
map<char,int>mp;
void solve() {
cin>>s;
int n=s.size();
int ans=0;
mp.clear();
for(int i=0;i<n;i++){
if(mp[s[i]]){
mp.clear();
ans+=2;
}
else {
mp[s[i]]=1;
}
}
cout<<n-ans<<"\n";
}
D
题意
给定一个长度为\(n\)且值域为\([-2,2]\)的数组,问从数组头和尾各删除多少个数,使得剩下的数组乘积最大。
ps:如果一个数组为空数组,那么这个数组的乘积默认为1.
数据范围
思路
首先,删除头尾各多少个数意味着子区间乘积最大,那么我们可以很显然的想到需要枚举子区间,然后我们会发现如果一个子区间中有0,那么这个区间的乘积也为0,那还不如整体全删掉,于是我们又可以想到的是通过0的位置进行分段。
那么对于一个子区间来说,我们只需要统计负号的数量以及区间中2的个数,当负号的个数为偶数的时候更新答案。然后需要分子区间的长度是奇数还是偶数讨论,如果是奇数那么需要考虑去掉队头和队尾,如果是偶数需要考虑去掉队头的两种情况,因为如果那个位置是-1,我们默认选了会导致答案没更新到。
代码
打的时候没脑子,又写复杂了,呜呜呜。
int n;
int a[N];
vector<int>v;
struct node {
int cnt,l,r;
}ans[N<<2];
bool cmp(node a,node b){
return a.cnt>b.cnt;
}
void solve() {
v.clear();
cin>>n;
int tot=0;
v.pb(0);
int ff=0;
for(int i=1;i<=n;i++){
cin>>a[i];
if(a[i]==0){
v.pb(i);
}
if(a[i]!=0){
ff=1;
}
}
v.pb(n+1);
for(int i=0;i<v.size()-1;i++){
int l=v[i]+1,r=v[i+1]-1;
int f=0,cnt=0;
for(int j=l;j<=r;j++){
if(a[j]<0){
f++;
}
if(abs(a[j])==2){
cnt++;
}
if(f%2==0){
ans[++tot].cnt=cnt;
ans[tot].l=l;
ans[tot].r=j;
}
}
f=0,cnt=0;
for(int j=l+1;j<=r;j++){
if(a[j]<0){
f++;
}
if(abs(a[j])==2){
cnt++;
}
if(f%2==0){
ans[++tot].cnt=cnt;
ans[tot].l=l+1;
ans[tot].r=j;
}
}
f=0,cnt=0;
for(int j=r-1;j>=l;j--){
if(a[j]<0){
f++;
}
if(abs(a[j])==2){
cnt++;
}
if(f%2==0){
ans[++tot].cnt=cnt;
ans[tot].l=j;
ans[tot].r=r-1;
}
}
f=0,cnt=0;
for(int j=r;j>=l;j--){
if(a[j]<0){
f++;
}
if(abs(a[j])==2){
cnt++;
}
if(f%2==0){
ans[++tot].cnt=cnt;
ans[tot].l=j;
ans[tot].r=r;
}
}
}
if(tot==0){
cout<<n<<" 0"<<"\n";
return ;
}
sort(ans+1,ans+1+tot,cmp);
// for(int i=1;i<=tot;i++){
// cout<<ans[i].cnt<<" "<<ans[i].l<<" "<<ans[i].r<<endl;
// }
cout<<ans[1].l-1<<" "<<n-ans[1].r<<"\n";
}
E
题意
给定一个\(n*n\)的\(01\)矩阵,对于这个矩阵我们可以有5种操作:
- 整体行往下循环,费用为\(0\)
- 整体行往上循环,费用为\(0\)
- 整体列往左循环,费用为\(0\)
- 整体列往右循环,费用为\(0\)
- 将一个点的值更改,费用为\(1\)
问最少的费用使得这个矩阵变换为\(unitary matrix\)。
PS:\(unitary matrix\)为一个矩阵的主对角线元素全为\(1\),其他元素为\(0\).
数据范围
思路
大水题,首先统计整个矩阵中\(1\)的数量为\(cnt\),并且对于每个主对角线往一个方向循环移动,\(check\)此时的对角线上\(1\)的个数为\(tot\),那么当前情况的最少改变费用即 \((cnt-tot)+(n-tot)\).
将上述情况的答案取\(min\)即答案。
代码
int n;
char a[N][N];
void solve() {
cin>>n;
int cnt=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>a[i][j];
if(a[i][j]=='1'){
cnt++;
}
}
}
int minn=n*n;
for(int i=1;i<=n;i++){
int sx=1,sy=i;
int tot=0;
for(int j=1;j<=n;j++){
if(a[sx][sy]=='1'){
tot++;
}
sx++;sy++;
if(sy==n+1){
sy=1;
}
}
minn=min(minn,(n-tot)+(cnt-tot));
}
cout<<minn<<"\n";
}
F1 - F2
题意
给定一个只由'-'和'+'构成的字符串,其中'--'可以替换成一个'+',如果一个字符串满足通过替换后'+'的数量和'-'的数量相同,那么称这个字符串为美丽的。
问:该字符串中美丽的子串数量。
数据范围
\(1\)<=\(s.size()\)<=\(2*10^{5}\)
思路
把'+'看成-1,把'-'看成+1,子段和为 3 的非负整数倍即为美丽的。
现在问题就转化为了一个二维数点问题。
例如
字符串=- - + - - - +
对应的=1 2 1 2 3 4 3
那么我们知道任何一个\([l,r]\)的子区间的和为\(a[r]-a[l-1]\);
现在我们知道子段和需要等于 3 的非负整数倍,假设我们当前这位的前缀和为4,
那么满足的数应该是\(4+k*3\) \((k<=0)\)
那么我们关于%3 建立三个树状数组统计在它位置前面的且比它小的数字的数量就行。
代码
const int INF=0x3f3f3f3f;//2147483647;
const int N=2e5+50,M=1e5+50;
const ll mod=998244353;
const int MAXN=4e5+50;
ll tot=0;
int b[MAXN];
ll pre[MAXN];
inline ll lowbit(ll x){
return x&(-x);
}
void updata(ll x,ll k){
for(ll i=x;i<=MAXN;i+=lowbit(i)){
pre[i]+=k;
}
}
ll query(ll x){
ll res=0;
for(ll i=x;i>0;i-=lowbit(i)){
res+=pre[i];
}
return res;
}
int n;
string s;
int a[N];
void solve() {
cin>>n>>s;
ll ans=0;
for(int i=0;i<s.size();i++){
if(s[i]=='+'){
a[i+1]=-1+a[i];
}
else {
a[i+1]=1+a[i];
}
}
for(int i=0;i<3;i++){
tot=0;
for(int j=0;j<=(n+1)*2+3;j++)pre[j]=0;
for(int j=0;j<=n;j++){
if((a[j]+n+1)%3==i){
b[++tot]=a[j]+n+1;
}
}
for(int j=1;j<=tot;j++){
ans+=query(b[j]);
updata(b[j],1);
}
}
cout<<ans<<"\n";
}