【bzoj4806~bzoj4808】炮车马后——象棋四连击

bzoj4806——炮

  题目传送门:bzoj4806

  这种题一看就是dp。。。我们可以设$ f[i][j][k] $表示处理到第$ i $行,有$ j $列没放炮,$ k $列只放了一个炮。接着分情况讨论:第$ i $行不放炮、放一个炮、放两个炮;放在只有一个炮的列上,还是放在没炮的列上。于是就可以快乐地列方程了:

  $ \begin{equation} \begin{split} f[i][j][k] &= f[i-1][j][k] \\ &+ (j+1)\cdot f[i-1][j+1][k-1] \\ &+ (k+1)\cdot f[i-1][j][k+1] \\ &+ \binom{j+2}{2} \cdot f[i-1][j+2][k-2] \\ &+ (j+1)\cdot k\cdot f[i-1][j+1][k] \\ &+ \binom{k+2}{2}\cdot f[i-1][j][k+2] \end{split} \end{equation} $

  另外,此题有双倍经验:bzoj1801(我是不会告诉你模数不一样的)

  代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<algorithm>
#include<queue>
#include<vector>
#define ll long long
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
#define inf 0x7fffffff
#define mod 999983
#define eps 1e-20
ll read()
{
    ll tmp=0; char c=getchar(),f=1;
    for(;c<'0'||'9'<c;c=getchar())if(c=='-')f=-1;
    for(;'0'<=c&&c<='9';c=getchar())tmp=tmp*10+c-'0';
    return tmp*f;
}
using namespace std;
ll f[110][110][110];
int n,m;
int main()
{
    int i,j,k;
    n=read(); m=read();
    f[0][m][0]=1;
    for(i=1;i<=n;i++)
        for(j=0;j<=m;j++)
            for(k=0;k+j<=m;k++){
                f[i][j][k]=f[i-1][j][k]+f[i-1][j][k+1]*(k+1)+f[i-1][j][k+2]*(k+2)*(k+1)/2+f[i-1][j+1][k]*k*(j+1);
                if(k)f[i][j][k]+=f[i-1][j+1][k-1]*(j+1);
                if(k>1)f[i][j][k]+=f[i-1][j+2][k-2]*(j+2)*(j+1)/2;
                f[i][j][k]%=mod;
            }
    ll ans=0;
    for(j=0;j<=m;j++)
        for(k=0;k+j<=m;k++)
            ans=(ans+f[n][j][k])%mod;
    printf("%lld\n",ans); 
}
bzoj4806

bzoj4807——车

  题目传送门:bzoj4807

  这题一看就是组合数。。。就是加了个高精度罢了。

  代码:

#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#define ll long long
#define ull unsigned long long
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
#define lowbit(x) (x& -x)
#define mod 1000000007
#define inf 0x3f3f3f3f
#define eps 1e-18
#define maxn 1000010
inline ll read(){ll tmp=0; char c=getchar(),f=1; for(;c<'0'||'9'<c;c=getchar())if(c=='-')f=-1; for(;'0'<=c&&c<='9';c=getchar())tmp=(tmp<<3)+(tmp<<1)+c-'0'; return tmp*f;}
inline ll power(ll a,ll b){ll ans=1; for(;b;b>>=1){if(b&1)ans=ans*a%mod; a=a*a%mod;} return ans;}
inline ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
inline void swap(int &a,int &b){int tmp=a; a=b; b=tmp;}
using namespace std;
struct hp{
    char num[60];
    friend hp operator * (hp a,int b){
        int tmp=0; hp c;
        memset(&c,0,sizeof(c));
        for(int i=0;i<50;i++){
            tmp=tmp+b*a.num[i];
            c.num[i]=tmp%10; tmp/=10;
        }
        return c;
    }
    void print(hp a){
        int k=49;
        while(k&&!a.num[k])--k;
        for(int i=k;i>=0;i--)
            printf("%d",a.num[i]);
        printf("\n");
    }
};
ll p[maxn],mn[maxn],tot[maxn];
int n,m,cnt=0;
void eular(int n)
{
    for(int i=2;i<=n;i++){
        if(!mn[i])mn[i]=++cnt,p[cnt]=i;
        for(int j=1;j<=mn[i]&&1ll*i*p[j]<=n;j++)
            mn[i*p[j]]=j;
    }
}
int main()
{
    n=read(); m=read();
    if(n<m)swap(n,m);
    eular(n);
    for(int i=1;i<=cnt;i++)
        for(ll j=p[i];j<=n;j*=p[i])
            tot[i]+=n/j;
    for(int i=1;i<=cnt;i++)
        for(ll j=p[i];j<=m;j*=p[i])
            tot[i]-=m/j;
    for(int i=1;i<=cnt;i++)
        for(ll j=p[i];j<=n-m;j*=p[i])
            tot[i]-=(n-m)/j;
    hp ans;
    memset(&ans,0,sizeof(ans)); ans.num[0]=1;
    for(int i=1;i<=cnt;i++)
        for(int j=1;j<=tot[i];j++)
            ans=ans*p[i];
    ans.print(ans);
}
bzoj4807

bzoj4808——马

  题目传送门:bzoj4808

  其实如果把棋盘相邻块黑白染色,那么我们可以发现马每跳一步只会跳到异色格,所以直接互相连边,跑二分图匹配就行了。

  听说您像我一样用dinic跑二分图匹配?那得加当前弧优化。(至少我要加才能过)

  另外,此题也有双倍经验:bzoj3175

  代码:

#include<cstdio>
#include<cstring>
#define min(a,b) (a<b?a:b)
#define inf 0x3f3f3f3f
using namespace std;
const int dx[8]={1,-1,2,-2,2,-2,1,-1},dy[8]={2,2,1,1,-1,-1,-2,-2};
struct edge{
    int to,nxt,flow;
}e[800010];
int fir[40010],lv[40010],q[40010],cur[40010];
int mp[210][210];
int n,m,S,T,tot=0;
void add(int x,int y,int flow)
{
    e[tot].to=y; e[tot].flow=flow; e[tot].nxt=fir[x]; fir[x]=tot++;
    e[tot].to=x; e[tot].flow=0; e[tot].nxt=fir[y]; fir[y]=tot++;
}
int dfs(int now,int flow)
{
    if(now==T)return flow;
    int tot=0;
    for(int i=cur[now];~i;i=e[i].nxt)
        if(e[i].flow&&lv[e[i].to]==lv[now]+1){
            cur[now]=i;
            int tmp=dfs(e[i].to,min(flow,e[i].flow));
            e[i].flow-=tmp; e[i^1].flow+=tmp;
            tot+=tmp; flow-=tmp;
            if(!flow)break;
        }
    return tot;
}
int dinic()
{
    int i,ans=0;
    while(1){
        for(i=0;i<=T;i++)lv[i]=0,cur[i]=fir[i];
        int h=1,t=1; q[1]=S; lv[S]=1;
        while(h<=t){
            for(i=fir[q[h]];~i;i=e[i].nxt)
                if(e[i].flow&&!lv[e[i].to]){
                    q[++t]=e[i].to; lv[e[i].to]=lv[q[h]]+1;
                }
            ++h;
        }
        if(!lv[T])return ans;
        int k=dfs(S,inf);
        while(k)ans+=k,k=dfs(S,inf);
    }
}
int main()
{
    memset(fir,255,sizeof(fir));
    scanf("%d%d",&n,&m); S=0; T=n*m+1;
    int cnt=0;
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
            scanf("%d",&mp[i][j]),cnt+=!mp[i][j];
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
            if((i^j)&1){
                for(int k=0;k<8;k++){
                    int xx=i+dx[k],yy=j+dy[k];
                    if(xx<0||xx>=n||yy<0||yy>=m)continue;
                    add(i*m+j+1,xx*m+yy+1,1); 
                }
            }
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
            if(!mp[i][j]){
                if((i^j)&1)add(S,i*m+j+1,1);
                else add(i*m+j+1,T,1);
            }
    printf("%d\n",cnt-dinic());
}
bzoj4808

bzoj4809——皇后

  题目传送门:bzoj4810

  其实数据水,爆搜就能过,而且这道题好像也没什么靠谱的解法。

  代码:

#include<cstdio>
int mp[20][20],vis0[20],vis1[40],vis2[40];
int n,ans=0;
void dfs(int now)
{
    if(now>n){
        ++ans; return;
    }
    for(int i=1;i<=n;i++)
        if(!mp[now][i]&&!vis0[i]&&!vis1[now+i]&&!vis2[n+now-i]){
            vis0[i]=1; vis1[now+i]=1; vis2[n+now-i]=1;
            dfs(now+1);
            vis0[i]=0; vis1[now+i]=0; vis2[n+now-i]=0;
        }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            scanf("%d",&mp[i][j]);
    dfs(1);
    printf("%d\n",ans);
}
bzoj4810

 

posted @ 2018-12-05 20:01  QuartZ_Z  阅读(138)  评论(0编辑  收藏  举报