递推集合2
T1:划分数列
设 fi表示从一到 i 最少可以划分的段数,fi =min ( fbi−1 , fci−1 ) +1
bi 表示以 i 结尾单调递增的一段的起点,ci 表示以 i 结尾单调递减的一段的起点
查看代码
int n,last,a,b[100005],c[100005],f[100005];
int main()
{
scanf("%d%d",&n,&last);
b[1]=1;
c[1]=1;
for(int i=2;i<=n;i++)
{
scanf("%d",&a);
if(a>=last) b[i]=b[i-1];
else b[i]=i;
if(a<=last) c[i]=c[i-1];
else c[i]=i;
last=a;
}
memset(f,1e7,sizeof(f));
f[0]=0;
f[1]=0;
for(int i=1;i<=n;i++) f[i]=min(f[b[i]-1]+1,f[c[i]-1]+1);
printf("%d",f[n]);
return 0;
}
T2:求 f 函数
真水
查看代码
int main()
{
int n;
while(1)
{
scanf("%d",&n);
if(n==0)break;
if(n<=101)printf("91\n");
else printf("%d\n",n-10);
}
return 0;
}
T3:无限序列
每第(i)次变化得来的数列为第(i-1)次+第(i-2)次
所以,相同地,第(i)个数列中1的数量为第(i-1)次+第(i-2)次。
由于a ~ b可以看为:(1~b) - (1 ~ a-1),前缀和,
1~i的数列中1的个数,可以看成是经过某两次变化得来的1的个数的和(a+b),其中这分别两次变化得来的数列的长度的和必须为i。
查看代码
int Q;
long long a,b,p[105];
long long f(long long x)
{
long long ans=0,j;
while(x)
{
j=1;
while(p[j+2]<=x) j++;
ans+=p[j];
x-=p[j+1];
}
return ans;
}
int main()
{
p[1]=1;p[2]=1;
for(int i=3;i<=100;i++) p[i]=p[i-1]+p[i-2];
scanf("%d",&Q);
for(int i=1;i<=Q;i++)
{
scanf("%lld%lld",&a,&b);
printf("%lld\n",f(b)-f(a-1));
}
return 0;
}
T4:序列个数
以序列 2 3 4 1 5 为例,横轴为数字,纵轴为位置,辣么 ai 可视为以(1,1)为左上角,(i,i)为右下角的矩阵中 1 的个数
ai - ai-1 表示一个 L 字形区域内 1 的个数。考虑从内到外一次填入 1,分为三种情况
y \ x | 1 | 2 | 3 | 4 | 5 |
1 | 0 | 1 | 0 | 0 | 0 |
2 | 0 | 0 | 1 | 0 | 0 |
3 | 0 | 0 | 0 | 1 | 0 |
4 | 1 | 0 | 0 | 0 | 0 |
5 | 0 | 0 | 0 | 0 | 0 |
查看代码
ll n, a[101000], mod=340610;
int main()
{
scanf("%lld", &n);
ll ans=1;
for(ll i=1; i<=n; i++)
{
scanf("%lld", &a[i]);
if(a[i]-a[i-1]==1) ans=(ans*(i*2-1-2*a[i-1]))%mod; // 共2*I-1个位置,内层已经放a[i-1]个互不冲突的1
if(a[i]-a[i-1]==2) ans=(ans*(i-a[i-1]-1)*(i-a[i-1]-1))%mod;// 两条臂上各放一个 1,内层已经放a[i-1]个互不冲突的1
if(a[i]-a[i-1]>2) ans=0;
}
printf("%lld",ans);
return 0;
}
T5:平铺方案
第i列上竖着放一个2 * 1的,方案数为 f(i-1)
第i列与第i-1列放一个2 * 2的,方案数为 f(i-2)
第i列与第i-1列横着放一个1 * 2的,方案数为 f(i-2)
至于那个漂亮的高精小板子,来自之前积累的当我想敲高精加
查看代码
#include<bits/stdc++.h>
using namespace std;
int f[300][100010],len[10010],t[10010];
void add(int k)
{
int x=0;
for(int i=0;i<=len[k-2];i++)
{
f[k][i]=f[k-2][i]+f[k-2][i]+x;
x=f[k][i]/10;
f[k][i]%=10;
}
len[k]=len[k-2];
if(x) f[k][++len[k]]=x;
x=0;
len[k]=max(len[k],len[k-1]);
for(int i=0;i<=len[k];i++)
{
f[k][i]=f[k][i]+f[k-1][i]+x;
x=f[k][i]/10;
f[k][i]%=10;
}
if(x) f[k][++len[k]]=x;
}
int main()
{
len[0]=len[1]=len[2]=0;
f[1][0]=1;
f[2][0]=3;
int q;
for(int i=3;i<=251;i++) add(i);
while(cin>>q)
{
for(int i=len[q];i>=0;i--) printf("%d",f[q][i]);
printf("\n");
}
return 0;
}