TopCoder SRM 567 Div2 1000 countPlacements

本文介绍了一种针对特定网格布局中必须作为山顶的格子进行计数的算法,并通过排列组合原理解决小球放置问题。该算法使用C++实现,涉及容斥原理和动态规划思想。

神tm这题有毒,模数是1e9+9不是1e9+7坑死我了

容易发现有些格子是必须作为山顶的,其余格子是不是山顶都是无所谓的。一个格子只要满足上方三个都不是’X’就必须作为一个山顶,因为没有别的山顶可以覆盖它了。可以统计出必须为山顶的格子有 ss 个,其它’X’的格子有 sX个。

套用排列组合经典的小球问题,就相当于将 NN 个不同的小球放入 sX 个盒子里,可以为空,其中 ss 个盒子必须有小球的方案数。枚举有几个必须放的盒子没放,容斥即可。

看到别人代码里似乎是DP,不太懂。。

//tc is healthy, just do it
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N=2501;
const int p=1e9+9;
int n,m,s,sX;
ll C[N][N];

class MountainsEasy {
public:
    int countPlacements( vector <string> a, int K );
};

int pd(int i,int j,vector<string> a){
    if (i==0) return 1;
    if (a[i-1][j]=='X') return 0;
    if (j>0&&a[i-1][j-1]=='X') return 0;
    if (j<m-1&&a[i-1][j+1]=='X') return 0;
    return 1;
}

void init(){
    for(int i=0;i<N;i++) C[i][0]=1;
    for(int i=1;i<N;i++)
     for(int j=1;j<=i;j++)
      C[i][j]=(C[i-1][j]+C[i-1][j-1])%p;
}

void Add(ll &x,ll y){
    x+=y;
    while(x<0) x+=p;
    while(x>=p) x-=p;
}

ll power(int a,int n){
    ll ans=1;
    for(ll sum=a;n;sum=sum*sum%p,n>>=1) if (n&1) ans=ans*sum%p;
    return ans;
}

int MountainsEasy::countPlacements(vector <string> a, int K) {
    n=a.size();m=a[0].size();sX=0,s=0;
    init();
    for(int i=0;i<n;i++)
     for(int j=0;j<m;j++)
      if (a[i][j]=='X'){
        sX++;
        if (pd(i,j,a)) s++;
      }
    int v=-1;ll ans=0;
    cout<<s<<' '<<sX;
    for(int i=0;i<=s;i++){
        v=-v;
        Add(ans,v*C[s][i]*power(sX-i,K)%p);
    }
    return (int) ans;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值