Zero Escape
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
题意:给你n个人的id,有两扇门,每个门有一个标号,我们记作A和B,现在我们要将n个人分成两组,进入两扇门中,当且仅当进入该门的所有人的id之和的digital root(数字根)等于该门的标号方可进入,问有多少种不同的分法。
放上出题人的解题报告
在这先解释一下什么是数字根,例如65536,它的数字根为7,方法是不断将各位数字相加,直到成1位数为止,即
65536->6+5+5+3+6=25->2+5=7
因此一个数的数字根只有可能是1~9,或许你会发现一个数 模9等于该数各位数字和模9,例如 33%9=6%9;
以下是证明:
关于数字根的问题,在此推荐可以去做做HDU 1013 Digital Roots
这样之后,我们便可以直接采用动态规划(背包类 取或不取)的思想来解决问题了
令s[i][j]表示使前i个人id之和的数字根为j的方法数,那么计算s[i][j]分为两部分,一部分为前i-1个人id之和的数字根为j,不取第i个人进入该门;另一部分则是前i-1个人id之和的数字根+第i个人的id产生新的数字根的方法数
即状态转移方程为s[i][j]=(s[i-1][k]+s[i-1][j])%mod;其中k为j-a[i],i表示第i个人,j从1到9,若算出的k小于等于0还需加上9。转移方程中的两项分别对应,当前i位取或不取。因为每个数字是由确定的两个数字组合加起来得到的,比如2,若其中一个为1,那么另外一个也一定为1。且存在这样的性质,若干个数,按给定的规则先加,或者分开加,再组合在一起,得到的结果是一样的。故可以先预先把所有的数加起来,若其和和A+B得到的结果相同,那么直接取s[n][a]+s[n][b]的值即可,若不同,那么只可以放在任意的一扇门中,分别判断一下即可。
直接上代码,若有疑问,欢迎讨论,谢谢
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<stdlib.h>
#include<cmath>
#include<string>
#include<algorithm>
#include<iostream>
#define exp 1e-10
using namespace std;
const int N = 100005;
const int inf = 1000000000;
const int mod = 258280327;
int a[N],s[N][10];
int digital(int x)//用于求数字根
{
x%=9;
if(!x)
x=9;
return x;
}
int main()
{
int t,n,A,B,sum,i,j,k,ans;
scanf("%d",&t);
while(t--)
{
sum=0;
scanf("%d%d%d",&n,&A,&B);
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum=digital(a[i]+sum);
}
if(sum==digital(A+B))//判断所有人的id之和的数字根是否与两扇门标号之和的数字根相等
{
memset(s,0,sizeof(s));
s[1][a[1]]=1;
for(i=2;i<=n;i++)
for(j=1;j<=9;j++)
{
k=j-a[i];
if(k<=0)
k+=9;
s[i][j]=(s[i-1][j]+s[i-1][k])%mod;
}
printf("%d\n",(s[n][A]+s[n][B])%mod);
}
else//若不相等,要么无解,要么是所有人仅能进入其中一扇门
{
ans=0;
if(sum==A||sum==B)
ans++;
printf("%d\n",ans);
}
}
return 0;
}菜鸟成长记

1763

被折叠的 条评论
为什么被折叠?



