NOIP2016Day2T1 number of combinations Luo Gu p2822 problem solving report

See the original title Luo Valley ( https://www.luogu.org/problem/show?pid=2822 )
NOIP the second day of the first title to use the knowledge of number theory:
50 points algorithm
most violent approach is the direct use of formula, seek What factorial playing table
65 points algorithm
on the basis of the enumeration of violence, the number of combinations of other computer side by side, a single set of data time complexity O (n ^ 3)
further optimization of violence (high precision) (highest score : 75)
side by side with high accuracy in addition to high-precision passenger when the violence on the basis of the enumeration, count the number of combinations, a single set of data time complexity O (n)
but might burst space, depending on the number of bits stored in your How many

90 points algorithm
we count combinations and one to one relationship between Pascal's Triangle Pascal's Triangle can draw recursive formula is probably f [i, j] = f [i-1, j] + f [i-1, j-1 ] before the entire array is initialized to 0, then f [i, 0] = 1 (i = 0 to max) to make an initialization, the relationship between the number and the combination of Pascal's triangle is one-Cij = f [i, j] , when the playing table for each number k modulo the Pascal triangle, i.e. f [i] [j] = f [i-1] [j]% k + f [i-1] [j-1] % k = (f [i- 1] [j] + f [i-1] [j-1]) each i from 0 to n, j min (i, m ) to remove the current after a number from 0% k If f [i] [j] == 0 then count ++, after a count output done like this can approach 10 and 13 points out. First posted Code:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int num[2005][2005];
int sum[2005][2005];
int k,t,m,n;
void deal(){
    memset(num,0,sizeof(num));
    for(int i=0;i<=2002;i++){
        num[i][0]=1;
    }
    for(int i=1;i<=2002;i++){
        for(int j=1;j<=i;j++){
            num[i][j]=(num[i-1][j]+num[i-1][j-1])%k;
        }
    }
}
int main()
{
    memset(sum,0,sizeof(sum));
    int count=0;
    scanf("%d%d",&t,&k);
    deal();
    for(int r=0;r<t;r++){
        scanf("%d%d",&m,&n);
        for(int i=0;i<=m;i++){
            for(int j=0;j<=min(i,n);j++){
                if(num[i][j]==0){
                    count++;
                }
            }
        }
        printf("%d\n",count);
        count=0;

    }
    return 0;
}

100 algorithm
dimensional prefix and processing, after each removal time complexity is O (1), this way the total time is about 3 times 90 times but this question can be AC (3110ms)
now talk about prefixes and issues:

Prefix and one-dimensional

This optimization is mainly used in a determined sequence, a [i] + a [ i + 1] + ...... + a [j] and in O (1) time.
DETAILED simple principle: a sum [i] represents (a [1] + a [ 2] + ...... + a [i]), wherein the sum [0] = 0, then (a [i] + a [ i + 1] + ...... + a [j ]) that is equal to the sum [j] -sum [i- 1].

And two-dimensional prefix

Similarly, there is a two-dimensional one-dimensional. A matrix for a, we can determine the sub-matrix [x1 ~ x2] [y1 ~ y2] in O (1) time and.

Provided sum [i] [j] is the sub-matrix [1 ~ i] [1 ~ j] and. By the inclusion-exclusion principle was:

sum[0][j]=sum[i][0]=0

a[x1~x2][y1~y2]=sum[x2][y2]-sum[x1-1][y2]-sum[x2][y1-1]+sum[x1-1][y1-1]

Application issues

Core two words: dimensionality reduction.

Face many high-dimensional problems, often prefix and dimension reduction method is first thought of.
On the basis of such dimension reduction on the further optimization can be achieved.
We now use the prefix and pre-processing each result, each time to output just fine

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 2016;
int num[MAXN][MAXN];
int sum[MAXN][MAXN];
int main()
{
    int T,k;
    scanf("%d%d",&T,&k);
    for(int i=0;i<MAXN;i++){
        num[i][0]=0;
        num[0][i]=1;
    }
    for(int i=1;i<MAXN;i++){
        for(int j=1;j<MAXN;j++){
            num[i][j]=(num[i][j-1]+num[i-1][j-1])%k; 
        }
    }
    for(int i=1;i<MAXN;i++){
        for(int j=1;j<i;j++){
            sum[j][i]=sum[j-1][i]+sum[j][i-1]-sum[j-1][i-1];
            if (num[j][i]==0){
                sum[j][i]++;
            } 
        }
        sum[i][i]=sum[i-1][i];          
        if(num[i][i]==0){
            sum[i][i]++;
        } 
    }
    for(int i=0;i<T;i++){
        int n,m;        
        scanf("%d%d",&n,&m);
        while(m>n){
            m--;
        }
        printf("%d\n",sum[m][n]);
//题目说明了0 <= j <= min(i,m),也就是m应要<=n; 
    }
    return 0;
}
Published 41 original articles · won praise 58 · views 60000 +

Guess you like

Origin blog.csdn.net/a1351937368/article/details/76907902