按照通过和赛后补题顺序:L、C、K、E、B、G、A、H、D。由于篇幅原因,这里提供了前五题。
L:Need Zero
根据题意,直接取出个位上的数字x,然后判断。由于x的范围只会在1到9中,对于所有偶数可以用5凑,对于5可以用2凑,其他的奇数用10凑。直接特判即可。
void solve()
{
string s;
cin>>s;
char lst=s[s.size()-1];
int lstn=int(lst-'0');
if(lst=='0') cout<<"1";
else
{
if(lstn%2==0) cout<<"5";
else if(lstn==5) cout<<"2";
else cout<<"10";
}
}
C:Array Covering
不难发现,如果希望最大化答案,我们只需要让数组最大值maxn在选择的区间 (l, r) 中的一端点(可能maxn在l处,也可能在r处),选择区间的另一个端点拓展到数组的一端。经过两次这样的变换,除了整个数组首尾两头的元素都变成数组最大值maxn。
请注意题目中说是开区间,意味着答案并不是maxn*n,而是排除数组的首尾元素会发生变化,答案应该是(n-2)*maxn+a[0]+a[n-1]
void solve()
{
ll n;
cin>>n;
vector<ll> a(n);
for(int i=0;i<n;i++) cin>>a[i];
if(n==1)
{
cout<<a[0]<<endl;
}
else
{
ll maxn=*max_element(a.begin(),a.end());
ll ans=a[0]+a[n-1]+(n-2)*maxn;
cout<<ans<<endl;
}
}
K:Constructive
Ad-Hoc题,看到给出的样例开始思考是否和奇偶性有关。显然考场上我们没空给出严谨证明,但是通过样例就可以知道n=1有解,n=2无解。继续把玩,考虑n=3时的情况。我们知道,对于数组中的所有元素都是正整数,求和的增长速度必然小于求积。所以我们从n的排列考虑(因为这是唯一可能让求和等于求积,不然剩下的情况只可能差距越来越大)。当n=3时,不难发现1 2 3这三个数正好满足求和等于求积。当拓展到n=4,4的排列不满足条件,显然,越往后越不可能满足条件。因此,只需要对输入进行n=1或3的特判,如果满足那么输出制定序列,不然无法构造。
void solve()
{
int n;
cin>>n;
if(n==1)
{
cout<<"YES"<<endl;
cout<<1<<endl;
}
else
{
if(n==3)
{
cout<<"YES"<<endl;
cout<<"1 2 3"<<endl;
}
else cout<<"NO"<<endl;
}
}
E:Block Game
如果对数据结构比较熟悉的话,看完题目就应该发现这就是一个循环队列(环状数组)。非常经典的“右端挤出去、左端插进来”。当然如果没有听说过也无妨,用deque双端队列能同样达到效果。
下面的代码是循环队列的解法,个人认为可以参考学习。deque思路类似,不再给出。
void solve()
{
int n;
ll k;
cin>>n>>k;
vector<ll> a(n);
for(int i=0;i<n;i++) cin>>a[i];
vector<ll> c(n+1);
for(int i=0;i<n;i++) c[i]=a[i];
c[n]=k;
ll ans=LLONG_MIN;
for(int i=0;i<=n;i++)
{
int j=(i-1+(n+1))%(n+1);
ll sum=c[i]+c[j];
ans=max(sum,ans);
}
cout<<ans<<endl;
}
B:Card Game
贪心、博弈背景,思维含量依旧在线。这道题具体讲讲心路历程。
最开始先读题,发现只需要对小苯的牌组进行排列,小红牌组无法更改顺序(这个也很关键,苯环讲题的时候有不少同学说没读出来这个含义)。认为优先的策略是田忌赛马,对两个卡组都sort一下,然后从左往右遍历对比a[i]与b[i],得到必胜牌数量,再计算答案。结果是本地跑了几组数据,WA了。
仔细想想,为什么田忌赛马不能解决这个题目?经过思考,我们构造了这组hack数据:
小苯:1、2、5
小红:3、4、6
如果按照上面的贪心思想,小苯在这个局面下没有得到一分。但是显然,我们可以用小苯的5对阵小红3,4中的一张牌,所以其实最少能得到1分。因此,我们需要改变贪心策略。
那么,干脆不改变小红的牌组顺序,对于小苯的牌组,根据上面的hack数据我们认识到,在这种局面下我们应该用“及时行乐”原则,把越大的牌越早出,直到剩下的牌无法盖过小红剩余牌组中的任何一张。
因此,对小苯的牌组进行降序排序,然后用双指针维护一个变量k,用来记录小苯手上的牌在本次游戏中最大能获得的分数。由于一张牌对应一分,所以也就是会有k张牌能被打出并移除。从性质上,小苯的整个牌堆分成可以打出和不可打出两种。方案数则为k!(n-k)!
void init() // 预处理阶乘 { f[0]=1; for(int i=1;i<=maxn;i++) f[i]=f[i-1]*i%modn; } void solve() { int n; cin>>n; vector<ll> a(n),b(n); for(int i=0;i<n;i++) cin>>a[i]; for(int i=0;i<n;i++) cin>>b[i]; sort(a.begin(),a.end(),greater<ll>()); int i=0,j=0,k=0; ll res=0; while(i<n&&j<n) { if(a[i]>b[j]) k++,i++; else j++; } res=f[k]*f[n-k]%modn; cout<<res<<endl; }

Comments NOTHING