公主殿下!!
骑士团参见公主殿下!!
公主殿下世界第一!!
做这道题之前先膜殿下一发
回正题
这道题是问这个数组能不能被分割为奇数个子串,每个子串的长度为奇数,且子串开头和结尾都是奇数
暴力把数组拆分为最多的符合题意的子串,即从左向右扫描,遇见能拆的就拆开,这样出来的子串数目一定是最多的
证明:假若当前可以拆分,那么当前不拆分的话,以后就没有机会拆分了。假若存在最优拆分方法使得当前不拆分的话,那么当前拆分,以后便采取最优的策略,这样的结果比最优还要好,因此能拆就拆是最好的。
其次,在拆分的过程中维护两个值,一个是奇数长度的子串数目,一个是偶数长度的子串数目。
最后的答案就是奇数长度的子串数目的奇偶性(奇数为Yes,偶数为No)
然后反对意见就是能不能通过合成一些子串使得最小串合成之后满足题意?
答案是不能
两个奇数长度子串能够合成一个偶数长度串,一个奇数长度串+偶数长度串是依然是奇数长度串。
因此也就是可以凭空减少两个奇数子串,因此最后的答案就是奇数子串的奇偶性。
PS: 最近在二刷Lisp,所以cout那一行可能会有点难看.......,不过记住逗号运算符是从左向右求值,返回结果是最右边的值就OK了
(尽量做到函数式编程,虽然这里没有体现出来)
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxm=110;
const char* str[2]{"No\n","Yes\n"};
int n,arr[maxm],num[2];
const char* handle();
int main(){
ios_base::sync_with_stdio(0);
cout<<(cin>>n, for_each(arr,arr+n,[](int& i){cin>>i;}), handle());
return 0;
}
const char* handle(){
if((arr[n-1]&1)&&(arr[0]&1)){
if(n&1)
return str[1];
int last=-1;
for(int i=0,has_begin=0;i<n;++i)
if((arr[i]&1)&&!has_begin)
has_begin=true,last=i;
else if((arr[i]&1)&&arr[i+1]&1)
++num[(i-last+1)&1],last=i+1;
++num[(n-last)&1];
return str[num[1]!=1&&(num[1]&1)];
}
return str[0];
}