Codeforces Round #695 (Div. 2)(A-C题)
比赛只A了一题,我还是不行啊,唉。
A. Wizard of Orz
题目链接:https://codeforces.com/contest/1467/problem/A
思路:既然要使得整数最大,那么首位那一定要是9,那么次位就是8,第三位可以是7或9,那么就选9,而要第三位选9,那么就必须在第二个面板为8时暂停,这么思路就确定了下来:
- 当n>=2时,在第二个面板为8时暂停第二个面板
- 当n=1时,那就是9了
代码如下:
#include<iostream>
using namespace std;
int main()
{
int T;
cin>>T;
int n;
while(T--)
{
cin>>n;
if(n==1) cout<<9;
else if(n==2) cout<<98;
else if(n==3)
{
cout<<989;
}
else
{
cout<<989;
n-=3;
for(int i=0;i<n;++i)
{
cout<<i%10;
}
}
cout<<endl;
}
return 0;
}
B. Hills And Valleys(模拟)
题目链接:https://codeforces.com/contest/1467/problem/B
思路:就是因为这样我才讨厌模拟啊
- n<=3,输出0
- n>=4时
把每个数当做是一个有高度的点,方便对山和谷的想象。对于每个点(除了第一个和最后一个)的位置模拟进行移动,其移动后位置有5种情况:- 在左右两点上面
- 和右边的点等高
- 与左边的点登高
- 在左右两点中间
- 在左右两点的下面
经过本人不细致的思索第2,3种情况的结果肯定是优于其余三种的,所以只要考虑第2,3种情况导致山与谷数目的变化。然后对于模拟每个点的移动,比较得出最小值最后得出最优解。代码如下:
#include<iostream>
#include<vector>
using namespace std;
bool is(int index);
int T;
int n;
int vec[1000000];
int main()
{
cin>>T;
while(T--)
{
int maxn=0,ans=0,tmp;
cin>>n;
for(int i=0;i<n;++i)
cin>>vec[i];
if(n<=3) cout<<0;
else
{
maxn=0;
for(int i=1;i<n-1;++i)
{
if(is(i)) ++ans;
tmp=vec[i];
int now=is(i-1)+is(i)+is(i+1);
vec[i]=max(vec[i+1],vec[i-1]);
int tran=is(i-1)+is(i)+is(i+1);
vec[i]=min(vec[i+1],vec[i-1]);
tran=min(tran,is(i-1)+is(i)+is(i+1) );
if(now-tran>maxn) maxn=now-tran;
vec[i]=tmp;
}
cout<<ans-maxn;
}
cout<<endl;
}
return 0;
}
bool is(int index)
{
if(index>=1&&index<=n-2)
{
if(vec[index]>vec[index-1]&&vec[index]>vec[index+1]) return 1;
if(vec[index]<vec[index-1]&&vec[index]<vec[index+1]) return 1;
}
return 0;
}
C - Three Bags(贪心)
参考这位巨佬的思路 https://www.cnblogs.com/AWCXV/p/14254240.html
题目链接:https://codeforces.com/contest/1467/problem/C
思路:
按照那位大佬的思路:(以下原话复制了,侵删)
把操作 (x,y) 看做是有向树的一条边,边由儿子节点指向父节点,其中儿子节点表示 y,父节点表示 x。
即操作过后, 儿子节点没了,父节点变成 x−y,直到只剩下一个根节点为止。
那么,形成的这棵树有 n1+n2+n3 个节点。
模拟一下会发现,最后剩下的一个数字就为树中偶数层的节点之和减去奇数层的节点之和(根视为第 0 层)。
问题就转化成让奇数层上数字之和最小。
下面是自己的理解
因为我们在奇数层里放的数受到条件的制约,但仍可以把问题分为三种情况:奇数层上的数来只自一个集合,奇数层上的数来自两个集合或奇数层上的数来自三个集合。最优解肯定能从三个里面选出。
- 首先分析来自一个集合的情况:
如果只来自一个集合,那么该集合里的所有数都应该放置在奇数层,如果存在一个数不位于奇数层,而位于第0层,模拟一下,那势必也会让其余集合内元素进入奇数层;如果存在元素位于除0外的偶数层,模拟一下同理也不行。
所以对于奇数层只来自一个集合,那么该集合内部所有元素都应放置于奇数层。而对于这种情况,假设三个集合内所有元素的总和分别为\(sum1,sum2,sum3,\)那么最优解就是\[ans1=max\{sum1+sum2-sum3,sum2+sum3-sum1,sum1+sum3-sum2\} \] - 如果来自两个集合:
设每个集合内的数的最小值分别为\(minn1\),\(minn2\),\(minn3\),如果我们以minn1所在的集合为最终结果所在的集合,那么很容易得到此时的最优解为\[sum1+sum2+sum3-minn2*2-minn3*2 \]简而言之就是把只minn2和minn3放在奇数层(实际上也肯定能做到)这样一来奇数层上的数字之和肯定就是最小的。所以最优解为:\[ans2=max\{sum1+sum2+sum3-minn2*2-minn3*2,sum1+sum2+sum3-minn1*2-minn2*2,sum1+sum2+sum3-minn1*2-minn3*2\} \] - 如果来自三个集合,不论实际上做不做到到,奇数层来自三个集合的最优解为:\[ans3=sum1+sum2+sum3-minn1*2-minn2*2-minn3*2 \]它肯定是要比第二种情况要小的,直接排除掉了。
所以最终的最优解就为:
代码如下:
#include<iostream>
#include<vector>
using namespace std;
typedef long long ll;
int main()
{
ll n1,n2,n3;
cin>>n1>>n2>>n3;
vector<ll> vec1(n1);
vector<ll> vec2(n2);
vector<ll> vec3(n3);
ll minn1=1e9,minn2=1e9,minn3=1e9,sum1=0,sum2=0,sum3=0;
for(int i=0;i<n1;++i)
{
cin>>vec1[i];
minn1=min(minn1,vec1[i]);
sum1+=vec1[i];
}
for(int i=0;i<n2;++i)
{
cin>>vec2[i];
minn2=min(minn2,vec2[i]);
sum2+=vec2[i];
}
for(int i=0;i<n3;++i)
{
cin>>vec3[i];
minn3=min(minn3,vec3[i]);
sum3+=vec3[i];
}
ll ans=0;
ans=max(ans,sum1+sum3-sum2);
ans=max(ans,sum1+sum2-sum3);
ans=max(ans,sum2+sum3-sum1);
ans=max(ans,sum1+sum2+sum3-minn1*2-minn2*2);
ans=max(ans,sum1+sum2+sum3-minn2*2-minn3*2);
ans=max(ans,sum1+sum2+sum3-minn1*2-minn3*2);
cout<<ans;
return 0;
}
D题往后不打算补了。
一点总结
- 对于比较复杂的贪心也要善于讨论不同情况,求出每个情况的最优解再从每个最优解里挑出结果的最优解。
考试周到了!好慌的说!!!