AmazingCounters.com

2017-2-26四校联考

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;
}

 

posted on 2017-02-26 15:58  ditoly  阅读(161)  评论(0编辑  收藏  举报