11.2 NOIP模拟赛 (morning)

来源:互联网 发布:淘宝烈风自行车怎么样 编辑:程序博客网 时间:2024/06/06 05:34

这里写图片描述

思路:

明显的DP,所以我考试时用的搜索............100的数据搜到 6*6 就爆了....尴尬 (0.0)还是来讲讲DP吧 这题有3种情况 一是 这列不放炮 二是放一个炮  三是放两个炮(这不废话么.....)那么 我们就开三维数组 f[k][i][j]代表前k行有i列放了一个炮有j列放了两个炮 那么没放炮的也很容易表示那么状态有如下几种1丶哪一列也不放炮时 f[k][i][j]=f[k-1][i][j]2丶在没有炮的一列放一个炮时   f[k][i][j]=f[k-1][i-1][j]*(m-i-j+1);   //由于当前状态是有i列有一个炮   //             j列有两个炮   //             (m-i-j)列没有炮   //所以推出它上一个状态 有(i-1)列有一个炮   //             j列有两个炮   //             (m-i-j+1)列没有炮   //没有炮的列都可以放炮 所以是f[k-1][i-1][j]*(m-i-j+1);   //其他状态大同小异就不详细解释了3丶在有一个炮的一列放一个炮    f[k][i][j]=f[k-1][i+1][j-1]*(i+1);4丶在没有炮的两列中各放一个炮   f[k][i][j]=f[k-1][i-2][j]*Q(m-j-i+2);//Q的具体含义见代码5丶在有一个炮的两列各放一个炮   f[k][i][j]=f[k-1][i+2][j-2]*Q(i+2);6丶在没有炮和有一个炮的两列中各放一个炮//等同于在没有炮的一列中放两个炮   f[k][i][j]=f[k-1][i][j-1]*(m-i-j+1)*i;

代码:

#include<cstdio>#include<iostream>#define MAXN 101#define MOD 999983#define ll long longusing namespace std;ll f[MAXN][MAXN][MAXN],ans;int n,m;inline void read(int&x) {    int f=1;x=0;char c=getchar();    while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}    while(c>='0'&&c<='9') x=10*x+c-48,c=getchar();    x=x*f;}inline int Q(int t) {    return t*(t-1)/2;}int main() {    freopen("cannon.in","r",stdin);    freopen("cannon.out","w",stdout);    read(n);read(m);    f[0][0][0]=1;    for(int k=1;k<=n;k++)      for(int i=0;i<=m;i++)        for(int j=0;j<=m-i;j++) {            f[k][i][j]=f[k-1][i][j];            if(i) f[k][i][j]+=f[k-1][i-1][j]*(m-i-j+1);            if(j&&i<m) f[k][i][j]+=f[k-1][i+1][j-1]*(i+1);            if(i>1) f[k][i][j]+=f[k-1][i-2][j]*Q(m-i-j+2);            if(j>1&&i<m-1) f[k][i][j]+=f[k-1][i+2][j-2]*Q(i+2);            if(i&&j) f[k][i][j]+=f[k-1][i][j-1]*(m-i-j+1)*i;            f[k][i][j]%=MOD;        }    for(int i=0;i<=m;i++)      for(int j=0;j<=m-i;j++)        ans=(ans+f[n][i][j])%MOD;    printf("%d\n",ans);    fclose(stdin);    fclose(stdout);    return 0;}

这里写图片描述

思路:

组合数....真是瞎了我的24K钛合金狗眼竟然看不出来我们让n>m所以n行中最多有m行可以放車也就是在n中选m个数一样的思路...求组合数可以先分解一下质因数 然后把除法去掉 对于只有乘法 只保留最后100位 最后  这要用高精!!!

代码:

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define rep(i,x,y) for(i=x;i<=y;i++)#define _rep(i,x,y) for(i=x;i>=y;i--)#define MIN(x,y) ((x)<(y)?(x):(y))const int MAXN=10000010;const int MAXLEN=50;int n,m,i,j;int tot[MAXN];bool pd[MAXN];struct bignumber{    int num;    int s[MAXLEN+1];    void clear(){num=0;memset(s,0,sizeof(s));}}ans,now;bignumber operator*(bignumber a,bignumber b){    int i,j;    bignumber c;c.clear();    rep(i,1,MIN(MAXLEN,a.num))    rep(j,1,MIN(MAXLEN-i+1,b.num))    c.s[i+j-1]+=a.s[i]*b.s[j];    rep(i,1,MAXLEN)    {           if(i<MAXLEN)c.s[i+1]+=c.s[i]/10;        c.s[i]%=10;    }    c.num=MAXLEN;while(c.num>1&&c.s[c.num]==0)c.num--;    return c;}bignumber pow(int x){    if(x==1)return now;    bignumber ans=pow(x/2);    ans=ans*ans;    if(x&1)ans=ans*now;    return ans;}void zhuan(int i){    now.clear();    while(i>0)now.s[++now.num]=i%10,i/=10;}void print(bignumber a){    int i;    _rep(i,a.num,1)printf("%d",a.s[i]);printf("\n");}int main(){    freopen("rook.in","r",stdin);    freopen("rook.out","w",stdout);    scanf("%d%d",&n,&m);    if(n<m)swap(n,m);    rep(i,1,m)tot[i]-=1;    rep(i,n-m+1,n)tot[i]+=1;    memset(pd,1,sizeof(pd));    rep(i,2,n)    if(pd[i])    _rep(j,n/i,2)    {        pd[i*j]=0;        tot[i]+=tot[i*j];        tot[j]+=tot[i*j];        tot[i*j]=0;    }    ans.num=1;ans.s[1]=1;    rep(i,2,n)if(tot[i]>0)zhuan(i),ans=ans*pow(tot[i]);    print(ans);    return 0;}

这里写图片描述
这里写图片描述

思路:

这个裸暴力只有70分 (尽管我暴力超时不要不要的)(0.0)实际上这题是可以用位运算优化的以行为阶段 记录之前每一列的信息和两条对角线的信息列好办 关键是这个对角线比较丑 因为他是斜着的假设当前行我们放在了i这里 那么下一行的话 就是i左边 和i右边不能放 这里利用位运算的左移右移就好了然后还有些小技巧 就是枚举当前行放在哪利用 lowbit 找最小的不是0的位在哪还有就是 状态记录的时候0表示还可以放但是涉及到 lowbit 这个 我们用的时候去一下反1 表示还可以放  这就非常优美了 

代码:

#include<cstdio>using namespace std;#define rep(i,x,y) for(i=x;i<=y;i++)const int MAXN=16;int n,i,j,x,ans;int a[MAXN];void search(int i,int S1,int S2,int S3){    if(i==n){ans++;return;}    int j,_S=((1<<n)-1)&(~(a[i]|S1|S2|S3));    while(_S>0)    {        j=_S&(-_S);        search(i+1,S1^j,(S2^j)>>1,(S3^j)<<1);        _S-=j;    }}int main(){    freopen("queen.in","r",stdin);    freopen("queen.out","w",stdout);    scanf("%d",&n);    rep(i,0,n-1)    rep(j,0,n-1)    scanf("%d",&x),a[i]+=x<<j;    search(0,0,0,0);    printf("%d\n",ans);    return 0;}
0 0
原创粉丝点击