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


    bzoj4806——炮

      题目传送门:bzoj4806

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

      $ egin{equation} egin{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] \ &+ inom{j+2}{2} cdot f[i-1][j+2][k-2] \ &+ (j+1)cdot kcdot f[i-1][j+1][k] \ &+ inom{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
    ",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("
    ");
        }
    };
    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
    ",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
    ",ans);
    }
    bzoj4810
  • 相关阅读:
    Django开发注意事项
    欧拉筛
    求小于n且与n互质的数的个数
    扩展欧几里得
    排列组合
    crc循环冗余检验
    求乘法逆元
    逆元
    4点共面
    Git学习笔记
  • 原文地址:https://www.cnblogs.com/quzhizhou/p/10072808.html
Copyright © 2020-2023  润新知