Codeforces Round #533 (Div. 2) C.思维dp D. 多源BFS

题目链接:https://codeforces.com/contest/1105

 

C. Ayoub and Lost Array

题目大意:一个长度为n的数组,数组的元素都在[L,R]之间,并且数组全部元素的和可以被3整除,问有多少种方法构建出该数组。答案模1000000007

输入
2 1 3
输出
3

note:满足的情况只有[1,2],[2,1],[3,3]

解题思路:用dp[i][j]表示长度为i的数组,元素大小在[L,R]之间,并且元素和模3的余数为j的方案数,我们可以计算出[L,R]范围内模3余0\1\2的数的个数,分别设为num0,num1,num2, 我们可以很容易知道dp[1][0]=num0,dp[1][1]=num1,dp[1][2]=num2,而dp[2][0]需要分情况,当前1个数和模3余0时,第2个数便只能放模3余0的数,即有dp[1][0]*num0种;当前1个数和模3余1时,第2个数便只能放模3余2的数,即有dp[1][1]*num2种;当前1个数和模3余2时,第2个数便只能放模3余1的数,即有dp[1][2]*num1种。dp[n][0]即为我们要求的答案。

于是我们便可以得出递推式:

dp[i][0]=((dp[i-1][0]*num0%mod+dp[i-1][1]*num2%mod)%mod+dp[i-1][2]*num1%mod)%mod;
dp[i][1]=((dp[i-1][0]*num1%mod+dp[i-1][1]*num0%mod)%mod+dp[i-1][2]*num2%mod)%mod;
dp[i][2]=((dp[i-1][0]*num2%mod+dp[i-1][1]*num1%mod)%mod+dp[i-1][2]*num0%mod)%mod;

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<string>
#include<set>
#include<cmath>
#include<list>
#include<deque>
#include<cstdlib>
#include<bitset>
#include<stack>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define pushup() tree[rt]=tree[rt<<1]+tree[rt<<1|1]
const int INF=0x3f3f3f3f;
const double PI=acos(-1.0);
const double eps=1e-6;
const ll mod=1e9+7;
const int maxn=100005;
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
ll dp[2000005][5];
ll n,l,r;
int main()
{
    ios::sync_with_stdio(false); cin.tie(0);
    cin>>n>>l>>r;
    ll num0=r/3-(l-1)/3;
    ll num1=num0;
    ll num2=num0;
    int i,j;
    for(i=l;i<=r;i++)
    {
        if(i%3==0)break;
        else if(i%3==1)num1++;
        else num2++;
    }
    for(j=r;j>=i;j--)
    {
        if(j%3==2)break;
        else if(j%3==1)
        {
            num2--; break;
        }
        else if(j%3==0)
        {
            num1--; num2--;
            break;
        }
    }
    dp[1][0]=num0; dp[1][1]=num1; dp[1][2]=num2;
    for(int i=2;i<=n;i++)
    {
        dp[i][0]=((dp[i-1][0]*num0%mod+dp[i-1][1]*num2%mod)%mod+dp[i-1][2]*num1%mod)%mod;
        dp[i][1]=((dp[i-1][0]*num1%mod+dp[i-1][1]*num0%mod)%mod+dp[i-1][2]*num2%mod)%mod;
        dp[i][2]=((dp[i-1][0]*num2%mod+dp[i-1][1]*num1%mod)%mod+dp[i-1][2]*num0%mod)%mod;
    }
    cout<<dp[n][0]<<endl;
    return 0;
}

 

 

 

D. Kilani and the Game

 

题目大意:给出一个n*m的地图,最多9个人,每个人至少含有一个城堡,同时有每个人的扩张速度,即可以连续扩张的次数,现在从1-n轮流从各自的城堡开始扩张,不可通过障碍,求整个地图被扩张完成后,各个人所占领城堡的数目。

Examples
input
3 3 2
1 1
1..
...
..2
output
6 3

解题思路:开始就是想bfs嵌套,先把每一个玩家从1-n的城堡压入第一个队列,再每次把第一个队列的第一个元素弹出,压入第二个队列继续进行bfs,,一直不知道哪里错了,看了别人博客后才发现那样是错的,如果那样做的话,对于这个样例是过不了的:

4 3 2
2 1
1..
1..
..2
...
如果那样做可能会输出9 3,而正确答案是10 2。
正确做法应该是每次将第一个队列相同编号的城堡压入到第二个队列,然后再对第二个队列进行bfs,这样就不会出现上面那种情况了
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<string>
#include<set>
#include<cmath>
#include<list>
#include<deque>
#include<cstdlib>
#include<bitset>
#include<stack>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define pushup() tree[rt]=tree[rt<<1]+tree[rt<<1|1]
const int INF=0x3f3f3f3f;
const double PI=acos(-1.0);
const double eps=1e-6;
const ll mod=1e9+7;
const int maxn=100005;
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
const int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
struct node{
    int x,y,id;
    node(int a,int b,int c):x(a),y(b),id(c){}
};
struct node1{
    int x,y,id,steps;
    node1(int a,int b,int c,int d):x(a),y(b),id(c),steps(d){}
};
int n,m,sump,s[10];
vector<node> p[10];
char mp[1050][1050];
queue<node> que;
queue<node1> que1;
void BFS()
{
    while(que.size())
    {
        node tmp=que.front();
        int id=tmp.id;
        que1.push(node1(tmp.x,tmp.y,tmp.id,0));
        while(que.size()&&que.front().id==id)  //判断第一个队列元素是否为当前压入队列是同一个玩家
        {
            que1.push(node1(que.front().x,que.front().y,que.front().id,0));
            que.pop();
        }
        while(que1.size())
        {
            node1 now=que1.front();
            que1.pop();
            if(now.steps==s[now.id]){
                que.push(node(now.x,now.y,now.id)); //走到最后一步继续压入第一个队列
                continue;
            }
            for(int i=0;i<4;i++){
                int dx=now.x+dir[i][0];
                int dy=now.y+dir[i][1];
                if(dx>=0&&dx<n&&dy>=0&&dy<m&&mp[dx][dy]=='.'){
                    mp[dx][dy]='0'+now.id;
                    que1.push(node1(dx,dy,now.id,now.steps+1));
                }
            }
        }
    }
}
int main()
{
    ios::sync_with_stdio(false); cin.tie(0);
    cin>>n>>m>>sump;
    for(int i=1;i<=sump;i++) cin>>s[i];
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            cin>>mp[i][j];
            if(mp[i][j]>='0'&&mp[i][j]<='9')
                p[mp[i][j]-'0'].push_back(node(i,j,mp[i][j]-'0'));  //同一个玩家的城堡压入同一个向量里
        }
    }
    for(int i=1;i<=sump;i++)
        for(int j=0;j<p[i].size();j++)
            que.push(p[i][j]);
    BFS();
    int ans[10];
    memset(ans,0,sizeof(ans));
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
            for(int k=1;k<=sump;k++)
                if(mp[i][j]==(k+'0'))
                    ans[k]++;
    cout<<ans[1];
    for(int i=2;i<=sump;i++)
        cout<<" "<<ans[i];
    cout<<endl;
    return 0;
}

 

posted @ 2019-01-22 13:36  两点够吗  阅读(167)  评论(0编辑  收藏  举报