The number of combinatorial problems problem solution P2822

This question Source: NOIP2016 improve group Day2T1

\ (90 \) points approach: first with \ (Pascal \) formula die \ (K \) in the sense \ (O (2000 ^ 2) \) pretreatment number of combinations of all the data range. For each query, violent enumeration \ (I \) and \ (J \) values, if the mode \ (K \) at this time has the meaning of the \ (\ ^ J C_i = 0 \) , described \ (\ c_i ^ j \) is \ (K \) multiples. Violence and updated statistics to answer.

\(code:\)

#include<bits/stdc++.h>//P2822 组合数问题
using namespace std;
#define re register
#define ll long long
#define il inline
#define dou double
#define un unsigned
il int read()
{
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
#define INF 114514114
#define clr(x) memset(x,0,sizeof(x))
#define N 2000+10
#define M 2000+10
#define T 10000+10
int t,k,ans;
int n[T],m[T];
ll C[N][M];
il void pascal()
{
    for(re int i=0;i<=2000;i++)
    {
        C[i][0]=1;
        for(re int j=1;j<=i;j++)
            C[i][j]=(C[i-1][j]%k+C[i-1][j-1]%k)%k;
    }
}
int main()
{
    t=read();k=read();
    pascal();
    for(re int i=1;i<=t;i++)
    {
        ans=0;
        n[i]=read();m[i]=read();
        for(re int j=0;j<=n[i];j++)
        {
            for(re int k=0;k<=min(j,m[i]);k++)
            {
                if(C[j][k]==0)ans++;
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}

\ (100 \) points approach: first with \ (Pascal \) formula die \ (K \) in the sense \ (O (2000 ^ 2) \) pretreatment number of combinations of all the data range. For each query, since \ (0 \ Leq I \ n-Leq \) , so \ (0 \ leq j \ leq min (i, m) \) is equivalent to \ (0 \ leq j \ leq min (n , m) \) . That is, we only required that the \ (0 \ Leq I \ n-Leq \) , \ (0 \ Leq J \ Leq min (n-, m) \) answers to a number in the range.

If violence enumeration \ (i \) and \ (j \) and violence statistics updated answer too slow. Consider using two-dimensional prefix and maintenance. You may use \ (Pascal \) maintain dimensional prefix and find the value of the number of combinations of simultaneous equations. Order \ (s [x] [y ] \) represents the \ (0 \ Leq I \ Leq X \) , \ (0 \ Leq J \ Leq Y \) number of answers in the range, then the metastasis \ (S [ x] [y] = s [ x-1] [y] + s [x] [y-1] -s [x-1] [y-1] + [C [x] [y] == 0] \) . Finally, output \ (s [n] [min (n, m)] \) of the value.

\(code:\)

#include<bits/stdc++.h>
using namespace std;
#define re register
#define ll long long
#define il inline
#define dou double
#define un unsigned
il int read()
{
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
#define INF 114514114
#define clr(x) memset(x,0,sizeof(x))
#define N 2000+10
#define M 2000+10
#define T 10000+10
int t,k,n,m;
int c[N][M],s[N][M];
il void pascal()
{
    for(re int i=0;i<=2000;i++)
    {
        c[i][0]=1;
        for(re int j=1;j<=i;j++)
        {
            c[i][j]=(c[i-1][j]%k+c[i-1][j-1]%k)%k;
            s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1];
            if(c[i][j]==0)s[i][j]++;
            s[i][j+1]=s[i][j];
        }
    }
}
int main()
{
    t=read();k=read();
    pascal();
    for(re int i=1;i<=t;i++)
    {
        n=read();m=read();
        cout<<s[n][min(n,m)]<<endl;
    }
    return 0;
}

Guess you like

Origin www.cnblogs.com/Hakurei-Reimu/p/11485570.html