Zero Escape
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 1008 Accepted Submission(s): 504
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 numbered X(1≤X≤9) , 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 door A , 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 .
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.
T≤100 , n≤105 , ∑n≤106 , 1≤A,B,idi≤9
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
1 0 10 60
给出一种操作A:把一个数的所有数字累加,替换为这个数,该步记为操作B;把操作B循环下去,最后得到一个数字。
规律是:一个数a可以在中间任意两个相邻位置断开为两个数x、y, x、y分别进行操作A,然后加起来,在进行操作A,最后结果与a进行A操作结果相同
而且这个结果与a%9相同。(由此可以无线分割)
证明: let a= c*(10^k )+d;
then c*(10^k)%9 =(10^k+10^k+10^k+.......+10^k)%9 (c个10^k )= c* ( 10^k %9 ) %9; =c*(1)%9 =c%9;
so a%9= ( c*(10^k) +d) %9 = ( c*(10^k)%9 +d%9 )%9= ( c%9 +d%9 )%9;
令f(x)=x%9;
把所有人的数字加起来%9 记为f(sum), 如果f(sum)==f(A+B),那么人群可以往A、B两个门走,如果f(sum)==f(A),可以往A门走,如果f(sum)==f(B)可以往B门走。
dp[i][x]表示考虑前i个人,凑出 f()为x的方法数,因为X只表示一个门,他所表示的另一个门,应该是 (f (sum(1,2,3...i) ) - f(A)(如果差<0再加9) )%9,这个门随着i的增加而变化。
这其实是一种两个方面配对死了,知道某一面就能知道另一面,然后抓住一个方面考虑问题的方法。
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<climits>
#include<queue>
#include<vector>
#include<map>
#include<sstream>
#include<set>
#include<stack>
#include<utility>
#pragma comment(linker, "/STACK:102400000,102400000")
#define PI 3.1415926535897932384626
#define eps 1e-10
#define sqr(x) ((x)*(x))
#define FOR0(i,n) for(int i=0 ;i<(n) ;i++)
#define FOR1(i,n) for(int i=1 ;i<=(n) ;i++)
#define FORD(i,n) for(int i=(n) ;i>=0 ;i--)
#define lson num<<1,le,mid
#define rson num<<1|1,mid+1,ri
#define MID int mid=(le+ri)>>1
#define zero(x)((x>0? x:-x)<1e-15)
using namespace std;
const int INF =0x3f3f3f3f;
const int maxn= 100000 +10 ;
//const int maxm= ;
//const int INF= ;
typedef long long ll;
const ll inf =1000000000000000;//1e15;
//ifstream fin("input.txt");
//ofstream fout("output.txt");
//fin.close();
//fout.close();
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
//by yskysker123
int dp[maxn][10];
int a[maxn];
int mod=258280327;
inline int f(int x)
{
return x%9;
}
int n,A,B,sum;
int main()
{
int T;scanf("%d",&T);
while(T--)
{
scanf("%d%d%d",&n,&A,&B);
sum=0;
FOR1(i,n)
{
scanf("%d",&a[i]);
sum+=a[i];
}
if(f(sum)!= f(A+B)&&f(sum)!=f(A) &&f(sum)!=f(B) )
{
puts("0");continue;
}
for(int i=0;i<=n;i++)
{
for(int j=0;j<=8;j++)
{
dp[i][j]=0;
}
}
dp[0][0]=1;
for(int i=1;i<=n;i++)
{
for(int j=0;j<=8;j++)
{
dp[i][j]=dp[i-1][j];
}
for(int j=0;j<=8;j++)
{
int x=f(j+a[i]);
dp[i][x]=(dp[i][x]+dp[i-1][j])%mod;
}
}
if( f(sum)!=f(A+B))
{
if(f(sum)==f(A)&&f(sum)==f(B))
{
puts("2") ; continue;
}
else
{
puts("1"); continue;
}
}
printf("%d\n",dp[n][f(A)]);
}
return 0;
}