cf刷题日记
样例输入1:
2
0 1
样例输出1:
4 1
1 2
样例输入2:
3
1 3 9
样例输出2
13 0
样例输入3:
4
1 100 2 1
样例输出3:
105 2
3 3
3 4
样例输入4:
1
0
样例输出4:
1 1
1 1
题目题意:
给你一个数组a,每次你可以选择数组的某一个子数组,然后用这个子数组的mex来替换这个子数组的所有元素,你可以最多执行5*10^5次该操作。题目求的是你可以得到的最大的数组a的和,操作数,以及具体的操作。(mex是该数组不包含的最小非负整数)
分析:
这个居然是cf的2000分的题目QAQ!!!,感觉分数有点虚高。
首先,如果有一个长度为x的数组,我们在对这个数组进行一系列的mex后,这个数组最大的和是x个x相加,即x*x,例如,如果x为5,我们先将这个数组变为全0,然后我们选择以下区间并对它进行mex操作:
1 1
1 2
2 2
2 2
1 3
2 3
2 2
2 3
3 3
3 3
1 4
2 4
2 2
2 3
3 3
3 3
2 4
3 4
3 3
3 4
4 4
4 4
1 5
经过这些操作和,这个数组全变为了5,并且,这个一定就是这个数组所能得到的最大值了。
然后,我们可以看到这个题目的n特别小,我们直接暴力求解,2^18才只有262144,用dfs找选择进行mex操作所有区间,每一个元素选与不选,0表示不选,1表示选。
举个列子,对于样例3,a数组为:1 100 2 1,我们dfs得到的最佳选择方法为0,0,1,1,就是只对[3,4],这个区间进行mex,最终得到了1,100,2,2。
注意,如果dfs得到的选择数组是1,0,1,1,那么要进行的mex操作的区间为[1,1],[3,4]。
这个题目代码如下:
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
int n,a[105],s,m,qwq[105],q[105],ma;
vector<pair<int,int> > ans;
//用dfs来找最佳选择区间
void dfs(int u)
{
if(u==n+1)
{
vector<int> qaq;
int cnt=0,sum=0;
for(int i=1;i<=n;i++)
{
if(q[i]==0)//为0,这个位置的元素还是原来的值
{
if(cnt)
{
qaq.push_back(cnt);
cnt=0;
}
sum+=a[i];
}
else cnt++;//为1,进行了mex,这个位置的值取决于该位置的的区间长度
}
if(cnt) qaq.push_back(cnt);
for(int i=0;i<qaq.size();i++)
{
sum+=qaq[i]*qaq[i]; //加上进行mex后的值
}
if(sum>ma)//如果比当前的最大值还大,就记录该选择
{
ma=sum;
for(int i=1;i<=n;i++) qwq[i]=q[i];
}
return;
}
q[u]=0;
dfs(u+1);
q[u]=1;
dfs(u+1);
}
//这个是该题目的难点,如何对一个区间进行一系列操作,来得到最大的值,用了一个递归
void print(int l,int r,int u)
{
for(int i=l;i<=r;i++)
{
ans.push_back(make_pair(l,i));
if(i==u) return;
if(l+1<=i) ans.push_back(make_pair(l+1,i));
print(l+1,i,u);
}
}
void solve()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
dfs(1);
int cnt=0;
qwq[n+1]=0;
for(int i0=1;i0<=n+1;i0++)//注意,这里是从1到n+1,最后这个n+1可以很好的解决边界问题
{
if(qwq[i0]) cnt++;
else
{
if(cnt==0) continue;//如果为cnt为0,就不用就行mex
//先将这一段变为全0,方便操作
int l=i0-cnt,r=i0-1,te=0;
for(int i=l;i<=r;i++) if(a[i]==0) te=1;
//如果这一段的mex为0,就只用一次mex,否则两次
for(int i=0;i<=te;i++)
ans.push_back(make_pair(l,r));
//储存答案
print(l,r,r);
cnt=0;
}
}
//输出答案,大功告成!!!
cout<<ma<<" "<<ans.size()<<endl;
for(int i=0;i<ans.size();i++)
cout<<ans[i].first<<" "<<ans[i].second<<endl;
}
signed main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int T=1;
// cin>>T;
while(T--) solve();
return 0;
}
如果有看不懂的地方,可以评论提问,作者现役acmer,看到了问题就会回答,如果有错误的地方作者也很乐意改正^_^