Codeforces Round #533 (Div. 2)(C,D)题解

比赛链接

Ayoub had an array aa of integers of size nn and this array had two interesting properties:

  • All the integers in the array were between ll and rr (inclusive).
  • The sum of all the elements was divisible by 33.

Unfortunately, Ayoub has lost his array, but he remembers the size of the array nn and the numbers ll and rr, so he asked you to find the number of ways to restore the array.

Since the answer could be very large, print it modulo 109+7109+7 (i.e. the remainder when dividing by 109+7109+7). In case there are no satisfying arrays (Ayoub has a wrong memory), print 00.

Input

The first and only line contains three integers nn, ll and rr (1≤n≤2⋅105,1≤l≤r≤1091≤n≤2⋅105,1≤l≤r≤109) — the size of the lost array and the range of numbers in the array.

Output

Print the remainder when dividing by 109+7109+7 the number of ways to restore the array.

Examples

input

Copy

2 1 3

output

3

input

3 2 2

output

1

input

9 9 99

output

711426616

Note

In the first example, the possible arrays are : [1,2],[2,1],[3,3][1,2],[2,1],[3,3].

In the second example, the only possible array is [2,2,2][2,2,2].

PS:题意:给出一个范围(l,r)让你在这个范围中找n个数,可找相同的数,最后使n个数的和能被3整除,问有多少种方式。

题解:想想自己比赛时推了半小时的组合数就想笑。首先我们要把这区间中余数为0,1,2的个数算出来。然后声明一个二维数组dp[n][x],表示选取n个数,最后余数是x的组合方式有多少种。

现在我们将各余数的个数算出来,s0表示余数为0数的个数,s1表示余数为1数的个数,s2表示余数为2数的个数。

初始化,dp[1][0]=s0,sp[1][1]=s1,dp[1][2]=s2;

然后我们很容易想到:选取n个数余和0的方式是选取n-1个数和余0再选一个余0的数+选取n-1个数和余1的数再选一个余2的数+选取n-1个数和余2的数,再选一个余1的数。同理可得出n个数余1的方式和n个数余2的方式。状态转移方程为:

        dp[i][0]=(dp[i][0]+dp[i-1][0]*s0+dp[i-1][1]*s2+dp[i-1][2]*s1)%mod;
        dp[i][1]=(dp[i][1]+dp[i-1][1]*s0+dp[i-1][2]*s2+dp[i-1][0]*s1)%mod;
        dp[i][2]=(dp[i][2]+dp[i-1][1]*s1+dp[i-1][2]*s0+dp[i-1][0]*s2)%mod;

代码:

#include <iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<stack>
#include<string>
const int maxn=2e5+10;
const int mod=1e9+7;
const int inf=1e8;
#define me(a,b) memset(a,b,sizeof(a))
#define lowbit(x) x&(-x)
#define mid (l+r)/2
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
typedef long long ll;
using namespace std;
ll dp[maxn][3];
int main()
{
    int n,l,r;
    scanf("%d%d%d",&n,&l,&r);
    int s0=r/3-(l-1)/3,s1=(r+1)/3-l/3,s2=(r+2)/3-(l+1)/3;//算各余数的个数
    me(dp,0);
    dp[1][0]=s0,dp[1][1]=s1,dp[1][2]=s2;
    for(int i=2;i<=n;i++)
    {
        dp[i][0]=(dp[i][0]+dp[i-1][0]*s0+dp[i-1][1]*s2+dp[i-1][2]*s1)%mod;
        dp[i][1]=(dp[i][1]+dp[i-1][1]*s0+dp[i-1][2]*s2+dp[i-1][0]*s1)%mod;
        dp[i][2]=(dp[i][2]+dp[i-1][1]*s1+dp[i-1][2]*s0+dp[i-1][0]*s2)%mod;
    }
    printf("%lld\n",dp[n][0]);
    return 0;
}

D. Kilani and the Game

Kilani is playing a game with his friends. This game can be represented as a grid of size n×mn×m, where each cell is either empty or blocked, and every player has one or more castles in some cells (there are no two castles in one cell).

The game is played in rounds. In each round players expand turn by turn: firstly, the first player expands, then the second player expands and so on. The expansion happens as follows: for each castle the player owns now, he tries to expand into the empty cells nearby. The player ii can expand from a cell with his castle to the empty cell if it's possible to reach it in at most sisi (where sisiis player's expansion speed) moves to the left, up, right or down without going through blocked cells or cells occupied by some other player's castle. The player examines the set of cells he can expand to and builds a castle in each of them at once. The turned is passed to the next player after that.

The game ends when no player can make a move. You are given the game field and speed of the expansion for each player. Kilani wants to know for each player how many cells he will control (have a castle their) after the game ends.

Input

The first line contains three integers nn, mm and pp (1≤n,m≤10001≤n,m≤1000, 1≤p≤91≤p≤9) — the size of the grid and the number of players.

The second line contains pp integers sisi (1≤s≤1091≤s≤109) — the speed of the expansion for every player.

The following nn lines describe the game grid. Each of them consists of mm symbols, where '.' denotes an empty cell, '#' denotes a blocked cell and digit xx (1≤x≤p1≤x≤p) denotes the castle owned by player xx.

It is guaranteed, that each player has at least one castle on the grid.

Output

Print pp integers — the number of cells controlled by each player after the game ends.

Examples

input

3 3 2
1 1
1..
...
..2

output

6 3 

input

3 4 4
1 1 1 1
....
#...
1234

output

1 4 3 3 

Note

The picture below show the game before it started, the game after the first round and game after the second round in the first example:

In the second example, the first player is "blocked" so he will not capture new cells for the entire game. All other player will expand up during the first two rounds and in the third round only the second player will move to the left.

题意:就是相当于有一个m*n的棋盘,除去有些位置被占领了(字符“#”表示),然后有s个玩家,开始每个玩家都有一个初始位置,且i号玩家每次可以走st[i](st数组存的每个玩家可以走的步数).每次可以向上下左右四个方向,只要是被前面的人走过,后面的人就不能再走了。问每个人最后能走多少格。

题解:首先我们每个玩家依次走,每次遍历标记一次,要是一个玩家依次可以走多步,就遍历多次。直到不能再走下去,细节看代码。

#include <iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<stack>
#include<string>
const int maxn=1e3+10;
const int mod=1e9+7;
const int inf=1e8;
#define me(a,b) memset(a,b,sizeof(a))
#define lowbit(x) x&(-x)
#define mid (l+r)/2
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
int dir[4][2]={0,1,0,-1,1,0,-1,0};
typedef long long ll;
using namespace std;
char maps[maxn][maxn];
int st[20],n,m,s;
int cnt[maxn][maxn];
struct node
{
    int x,y;
};
queue<node>q[10],qu;
int check(int x,int y)
{
    if(x<0||x>=m||y<0||y>=n||cnt[x][y]||maps[x][y]=='#')
        return 0;
    return 1;
}
int bfs(int st)
{
    node now,next;
    int len=q[st].size();///这里不能直接将q[st].size()写到for循环里。
    for(int i=0;i<len;i++)
    {
        qu.push(q[st].front());///将当前玩家上一次能到的位置,然后现在以这些点为起点,继续扩散
        q[st].pop();
    }
    while(!qu.empty())
    {
        now=qu.front();
        qu.pop();
        for(int i=0;i<4;i++)
        {
            next.x=now.x+dir[i][0];
            next.y=now.y+dir[i][1];
            if(check(next.x,next.y))
            {
                cnt[next.x][next.y]=st;///每次标记当前位置被走过
                q[st].push(next);///把扩散的点放进队列组里面,方便下一次扩散
            }
        }
    }
    return q[st].size();///要是返回值为0,说明当前玩家已经走不了。
}
int main()
{
    scanf("%d%d%d",&m,&n,&s);
    for(int i=1;i<=s;i++)
        scanf("%d",&st[i]);
    for(int i=0;i<m;i++)
        scanf("%s",maps[i]);
    node now;
    for(int i=0;i<m;i++)
        for(int j=0;j<n;j++)
            if(maps[i][j]>='0'&&maps[i][j]<='9')
            {
                int temp=maps[i][j]-'0';
                now.x=i,now.y=j,cnt[i][j]=temp;
                q[temp].push(now);///q[i],表示第i个玩家下一步可以走的位置。
            }
    int flog=1;
    while(flog)
    {
        flog=0;
        for(int i=1;i<=s;i++)
            for(int j=1;j<=st[i];j++)//这里循环一个速度可以看成扩散多少次
            {
                if(bfs(i))
                    flog=1;
                else///要是当前这个人不能再走了,就跳过这个人。
                    break ;
            }
    }
    int ans[20];me(ans,0);
    for(int i=0;i<m;i++)
        for(int j=0;j<n;j++)
            ans[cnt[i][j]]++;///计算每个玩家走了哪些位置。
    for(int i=1;i<=s;i++)
        printf("%d ",ans[i]);
    printf("\n");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41292370/article/details/86583144