CF1268B Domino for Young
一个思维喵喵题,出的很好,很喜欢
肯定是奇偶分析的,对于每一列讨论,如果当前这一列为偶数,那么一定是可以塞满的,无论旁边是奇数个,还是偶数个,都可以横着或者竖着的拼。其实本题的难点就是讨论奇数个的列,因为如果只考虑单列,会空出来一个,那么就要将这个空和其他空结合。
看了一眼其他的题解,写的都很好,很严谨。但是我做这题的时候没想这么多,感性的证明了一下。
结论:对于所有奇数个数的列,一个奇数位和一个偶数位相对应可以多拼一个出来。
先感性的理解一下,如果两个位置之间隔着奇数列(即两个奇数个数的列,位置奇偶性也相同),那么中间的那几列只能独立完成拼接,而不能传递旁边两列的空。如果两个位置之间隔着偶数列(即两个奇数个数的列,位置奇偶性不同),那么中间是可以完成传递的,只用考虑最后两列,全部横着交错拼就行。
具体证明如下:
旁边两列奇数列减去
如果两个奇数列中间隔着奇数列是无解的,如图
那么其实横着根据奇偶传递是不能满足最后一列最后一个,和前一列下面最后一个同时空着。
如果两个奇数列中间隔着偶数列是有解的,如图
是可以通过技偶传递,满足最后一列最后一个,和前一列下面最后一个同时空着。
那么答案就可以算了,对于每个数上面可以完全拼完,所以每一列的初始贡献就是
那么综上所述,答案就是
代码如下:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<vector>
#include<set>
#include<string>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<functional>
#define ll long long
using namespace std;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
inline int read()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+c-'0',c=getchar();}
return x*f;
}
const int N=3e5+10;
int a[N];
int main()
{
int n=read();
for(int i=1;i<=n;i++)a[i]=read();
ll x=0,y=0,ans=0;
for(int i=1;i<=n;i++)
{
ans+=a[i]/2;
if(a[i]&1)
{
if(i&1)x++;
else y++;
}
}
cout<<ans+min(x,y)<<endl;
return 0;
}