hdu5389 Zero Escape DP+滚动数组 多校联合第八场

Zero Escape

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 56    Accepted Submission(s): 18


Problem Description
Zero Escape, is a visual novel adventure video game directed by Kotaro Uchikoshi (you may hear about ever17?

) and developed by Chunsoft.

Stilwell is enjoying the first chapter of this series, and in this chapter digital root is an important factor.

This is the definition of digital root on Wikipedia:
The digital root of a non-negative integer is the single digit value obtained by an iterative process of summing digits, on each iteration using the result from the previous iteration to compute a digit sum. The process continues until a single-digit number is reached.
For example, the digital root of 65536 is 7, because 6+5+5+3+6=25 and 2+5=7.

In the game, every player has a special identifier. Maybe two players have the same identifier, but they are different players. If a group of players want to get into a door numberedX(1X9), the digital root of their identifier sum must be X.
For example, players {1,2,6} can get into the door 9, but players {2,3,3} can't.

There is two doors, numbered A and B. Maybe A=B, but they are two different door.
And there is n players, everyone must get into one of these two doors. Some players will get into the doorA, and others will get into the door B.
For example:
players are {1,2,6},A=9,B=1
There is only one way to distribute the players: all players get into the door 9. Because there is no player to get into the door 1, the digital root limit of this door will be ignored.

Given the identifier of every player, please calculate how many kinds of methods are there,mod 258280327.

 

Input
The first line of the input contains a single number T, the number of test cases.
For each test case, the first line contains three integers n,A and B.
Next line contains n integers idi, describing the identifier of every player.
T100,n105,n106,1A,B,idi9
 

Output
For each test case, output a single integer in a single line, the number of ways that thesen players can get into these two doors.
 

Sample Input
4 3 9 1 1 2 6 3 9 1 2 3 3 5 2 3 1 1 1 1 1 9 9 9 1 2 3 4 5 6 7 8 9
 

Sample Output
1 0 10 60

  把N个数分成两组。一组加起来是A,一组加起来是B,1<=A,B<=9,也能够全分到同一组。当中加是依照他给的规则加。就是一位一位加。超过一位数了再拆分成一位一位加。

  由于把N个数全加起来再依照那个规则处理和两个两个加是一样的。用dp[i][j][k]表示前i个数分两组。第一组和为j,第二组和为k有多少种,直接依据a[i]和dp[i-1]的情况递推即可了(假设当前和为j,这一位是a[i],若j>a[i],上一位要取的是j-a[i],否则上一位是9-(a[i]-j),尽管和一般加法不一样,但也差不了多少)。这里N非常大,用滚动数组。但我一開始交上去超时,然后发现j和k不须要两重循环。由于前i个数的和是确定的,那么假设j确定了。k也确定了,所以能够先预处理前缀和(按他这样的加法规则的和)。每次依据j直接算出k。这里特别要注意j,k等于0的情况,进行特殊处理。

#include<cstring>
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<queue>
#define INF 0x3f3f3f3f
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

typedef long long LL;

const int MAXN=100010;
const LL MOD= 258280327;

int T,N,A,B;
int a[MAXN],sum[MAXN];
LL dp[2][10][10];

int cal(int i,int j){
    if(j>i) return j-i;
    return 9-(i-j);
}

int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d%d%d",&N,&A,&B);
        memset(dp,0,sizeof(dp));
        sum[0]=0;
        for(int i=1;i<=N;i++){
            scanf("%d",&a[i]);
            sum[i]=sum[i-1]+a[i];
            if(sum[i]>=10) sum[i]-=9;
        }
        int cur=0;
        dp[cur][a[1]][0]=1;
        dp[cur][0][a[1]]=1;
        for(int i=2;i<=N;i++){
            cur=!cur;
            memset(dp[cur],0,sizeof(dp[cur]));
            for(int j=0;j<=9;j++){
                int k;
                if(j==0) k=sum[i];
                else k=cal(j,sum[i]);
                if(j==a[i]) dp[cur][j][k]=(dp[cur][j][k]+dp[!cur][0][k])%MOD;
                if(k==a[i]) dp[cur][j][k]=(dp[cur][j][k]+dp[!cur][j][0])%MOD;
                if(j>0){
                    int t=cal(a[i],j);
                    dp[cur][j][k]=(dp[cur][j][k]+dp[!cur][t][k])%MOD;
                }
                if(k>0){
                    int t=cal(a[i],k);
                    dp[cur][j][k]=(dp[cur][j][k]+dp[!cur][j][t])%MOD;
                }
                //j==sum[i]时k可能为0
                if(j==sum[i]){
                    k=0;
                    if(j==a[i]) dp[cur][j][k]=(dp[cur][j][k]+dp[!cur][0][k])%MOD;
                    if(k==a[i]) dp[cur][j][k]=(dp[cur][j][k]+dp[!cur][j][0])%MOD;
                    if(j>0){
                        int t=cal(a[i],j);
                        dp[cur][j][k]=(dp[cur][j][k]+dp[!cur][t][k])%MOD;
                    }
                    if(k>0){
                        int t=cal(a[i],k);
                        dp[cur][j][k]=(dp[cur][j][k]+dp[!cur][j][t])%MOD;
                    }
                }
            }
        }
        LL ans=(dp[cur][A][0]+dp[cur][0][B]+dp[cur][A][B])%MOD;
        printf("%I64d
",ans);
    }
    return 0;
}



原文地址:https://www.cnblogs.com/clnchanpin/p/7097658.html