涉及到数学问题,数学题具有灵活多变的特点,对什么样的数(和数,阶乘数,二进制数等)进行拆分,以及如何拆分(乘法拆分,质因子拆分,因子拆分),都非常值得我们思考,此外,数学题具有严苛的时空限制,这使得数学问题形式更加灵活。
拆分目的:优化时空,复杂问题简单化。
经典例题 1:
合并:
一共有T组数据。每次可以将相邻两个数合并到一起,问最少多少次数可以让当前序列的数都相等
题目描述
1 2 3 1 1 1 其中一种情况
-> 3 3 1 1 1 将第一个与第二个合并
-> 3 3 2 1 将第三个和第四个合并
-> 3 3 3 将第三个和第四个合并
最短3次操作
Input
第一行为 T
接下来 T 组数据
第一行为N 第二行为a1-an
Output
输出最小次数
Sample Input
1
6
1 2 3 1 1 1
Sample Output
3
说明/提示
( 0≤ai≤1e6) (1≤N≤1e5), (1≤T≤10)
注意到,如果合并若干次后可以让当前序列的数都相等假设等于 cur ,最终得到的数组 假设有 k 个元素那sum{a[ 1 ],,,,,,a[ n ] }=k*cur;
预处理出 sum 的值 ,cur 时sum 的一个因子,那么从 最小的cur 开始枚举,看最终数组是否能划分成 k 组 即可 。
(注意 此题数据范围 2 e 5,该范围内 一个数的因字数最多有 240个);
AC 代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+9;
int n,m;
int a[N];
int tt;
int main(){
cin>>tt;
while(tt--)
{
int n;
int ans=0;
cin>>n;
int s=0;
for(int i=1;i<=n;i++) cin>>a[i],s+=a[i];
if(s!=0)
{
vector<int>fac(240);
int cnt=0;
for(int i=1;i<=s;i++)
{
if(s%i==0) fac[cnt++]=i;
}
for(int i=0;i<240;i++)
{
int fa=fac[i];
int res=0;
for(int j=1;j<=n;j++)
{
res+=a[j];
if(res>fa)
{
break;
}
if(res==fa) res=0;
}
if(res==0)
{
ans=fa;
break;
}
}
cout<<n-s/ans<<endl;
}
else cout<<0<<endl;
}
return 0;
}