T2正解是什么生成函数、插值等等等理论,被我组合数水过去了,T3看了看不会,最后因为出题人数据没做好T3没测,我过了两题,假装AK了。200/300
T1.矩形
题目大意:给定一个2*n的数字矩阵,将其划分为m个子矩阵,要求最小化子矩阵和的最大值,求这个值。(n<=100,000,m<=min(100,2*n),矩阵中元素均为正整数)
思路:最小化最大值,先无脑二分个答案,又发现只要求出最少分几块,不超过m就可行(从一个可行方案中多切一块一定也可行)。f[i]表示前2*i的矩阵分成若干个和不超过当前二分出的答案至少要几块,每次转移有两种情况:1.取宽度为2的子矩阵,前缀和一下二分到能取的最远的就行了;2.取两行宽度为1的拼起来,可以这么做:先预处理出每个格子作为块的末尾向前能走到最远的格子,然后每次转移开两个指针(假设叫j和k),分别表示两列目前选的分别覆盖到第一行的j+1~i和第二行的k+1~i,一开始j和k都设为i,每次取出较大者根据预处理的信息多取一段,并更新f[i]=f[max(j,k)]+目前选的段数,选超过m段就可以退出了。总复杂度O(n(m+logn)log)。
#include<cstdio> #include<algorithm> #include<iostream> using namespace std; #define ll long long char B[1<<26],*S=B,C;int X; inline int read() { while((C=*S++)<'0'||C>'9'); for(X=C-'0';(C=*S++)>='0'&&C<='9';)X=(X<<3)+(X<<1)+C-'0'; return X; } #define MN 100000 #define INF 0x3FFFFFFF ll a[MN+5],b[MN+5],c[MN+5]; int n,m,ta[MN+5],tb[MN+5],fa[MN+5],fb[MN+5],f[MN+5]; bool check(ll x) { int i,j,k,l; for(i=1;i<=n;++i) fa[i]=fa[ta[i]=lower_bound(a,a+i,a[i]-x)-a]+1, fb[i]=fb[tb[i]=lower_bound(b,b+i,b[i]-x)-b]+1; if(fa[n]>m||fb[n]>m)return false; for(i=1;i<=n;++i) { f[i]=c[i]-c[i-1]>x?INF:f[lower_bound(c,c+i,c[i]-x)-c]+1; for(j=k=i,l=1;l<=m&&(j||k);++l)j>k?j=ta[j]:k=tb[k],f[i]=min(f[i],f[max(j,k)]+l); if(f[i]>m)return false; } return true; } int main() { freopen("rec.in","r",stdin); freopen("rec.out","w",stdout); fread(B,1,1<<26,stdin); int i;ll l=0,r,x,mid,ans; n=read();m=read(); for(i=1;i<=n;++i)x=read(),l=max(l,x),a[i]=a[i-1]+x; for(i=1;i<=n;++i)x=read(),l=max(l,x),b[i]=b[i-1]+x,c[i]=a[i]+b[i]; for(r=c[n];l<=r;) if(check(mid=l+r>>1))ans=mid,r=mid-1; else l=mid+1; cout<<ans; fclose(stdin);fclose(stdout);return 0; }
T2.数列
题目大意:给出n,k,定义一个数列的权值为各项乘积,求所有和为n且不超过k项的正整数数列的权值和。(n<=10^9,k<=30000)
思路:考虑到k比较小,我们枚举数列的项数i,把n分成i个数,求各项乘积,相当于求把n个物品分成i段,每段各选出一个物品的方案数,发现只要确定每一段中选的物品在段内前面有多少个不选的物品,后面有多少个不选的物品,就能确定一个方案,先强制每段分1,问题转化为把n-i分成2i个非负整数的方案数,容易得出组合公式,答案即为Σ(i=1~k)C(n+i-1,2i-1)。这个式子可以O(k)计算,注意特判n<k。//出题人的做法复杂度是O(klogk)的好像。
#include<cstdio> #define MOD 998244353 #define MK 60000 int f[MK+5],v[MK+5]; int inv(int x) { int t=x,y=MOD-3; for(;y;t=1LL*t*t%MOD,y>>=1)if(y&1)x=1LL*x*t%MOD; return x; } int main() { freopen("seq.in","r",stdin); freopen("seq.out","w",stdout); int n,k,i,ans=0,x,y=1; scanf("%d%d",&n,&k);if(k>n)k=n;x=n; for(f[0]=i=1;i<k<<1;++i)f[i]=1LL*f[i-1]*i%MOD; for(--i,v[i]=inv(f[i]);i--;)v[i]=1LL*v[i+1]*(i+1)%MOD; for(i=1;i<=k;++i) { ans=(ans+1LL*x*y)%MOD; x=1LL*x*(n+i)%MOD*(n-i)%MOD; y=1LL*y*v[(i<<1)+1]%MOD*f[(i<<1)-1]%MOD; } printf("%d",ans); fclose(stdin);fclose(stdout);return 0; }