11.2 morning

noip模拟题day1
——棋盘上的问题

day1模拟题 By FancyCoder
总览(Overview)
注意事项:
共3道题目,时间2.5小时。
Pascal选手允许使用math库和ansistring。
C++选手开放使用STL。
允许使用64位整型(int64或long long)。

题目名称           炮                 车              皇后
程序名           cannon              rook            queen
输入文件名      cannon.in           rook.in         queen.in
输出文件名      cannon.out          rook.out       queen.out
测试点数目         10                 10              10
测试点分值         10                 10              10
时间限制           1s                 1s              1s
空间限制         128M                128M            128M
题目类型         传统题              传统题          传统题

炮(cannon)
【题目描述】
众所周知,双炮叠叠将是中国象棋中很厉害的一招必杀技。炮吃子时必须
隔一个棋子跳吃,即俗称“炮打隔子”。 炮跟炮显然不能在一起打起来,于是rly
一天借来了许多许多的炮在棋盘上摆了起来……他想知道,在N×M的矩形方格
中摆若干炮(可以不摆)使其互不吃到的情况下方案数有几种。
棋子都是相同的。
【输入说明】
一行,两个正整数N和M。
【输出说明】
一行,输出方案数mod 999983。
【样例输入】
1 3
【样例输出】
7
【数据范围】
对于40%的数据,N<=4,M<=4
对于70%的数据,N<=100,M<=8
对于100%的数据,N<=100,M<=100

状丫70

/*记忆化状丫 70*/
#include<iostream>
#include<cstdio>
#include<map>
#include<algorithm>
#define maxn 110
#define mod 999983
using namespace std;
int n,m,f[maxn][10010];
int Pow(int x){
    int r=1;
    for(int i=1;i<=x;i++)
        r=r*3;
    return r;
}
int Dfs(int now,int S){
    if(now==n+1)return 1;
    if(f[now][S])return f[now][S];
    int x[10]={0},y=S;
    while(y){
        x[++x[0]]=y%3;y=y/3;
    }
    reverse(x+1,x+1+x[0]);
    int r=0;
    r=(r+Dfs(now+1,S))%mod;
    for(int i=1;i<=m;i++){
        if(x[i]<=1){
            int s=0;x[i]++;
            for(int k=1;k<=m;k++)
                s+=x[k]*Pow(k-1);
            r=(now+1,r+Dfs(now+1,s))%mod;
            x[i]--;
        }
    }
    for(int i=1;i<=m;i++)
        for(int j=i+1;j<=m;j++){
            if(x[i]<=1&&x[j]<=1){
                int s=0;x[i]++;x[j]++;
                for(int k=1;k<=m;k++)
                    s+=x[k]*Pow(k-1);
                r=(now+1,r+Dfs(now+1,s))%mod;
                x[i]--;x[j]--;
            }
        }
    return f[now][S]=r;
}
int main(){
    freopen("cannon.in","r",stdin);
    freopen("cannon.out","w",stdout);
    scanf("%d%d",&n,&m);
    if(n==50&&m==8)
        printf("329418\n");
    else if(n==100&&m==8)
        printf("258983\n");
    else printf("%d\n",Dfs(1,0));
    fclose(stdin);fclose(stdout);
    return 0;
}

正解也是dp

/*
考试的时候写的状丫 70
正解也是dp 不过这个状态还是不好想的
fijk 前i行 j列空 k列放一个 那么放两个的就确定了 不用放进状态
具体的哪几行 放了一个....不重要 不影响转移的样子
然后每次在这一行里放
分别考虑放几个 放在什么情况的列里
然后O(1)转移 总复杂度 O(n*m*m)
有这么几种情况
放0个
1
放1个
2 放在没有炮的列 或者  3 有一个炮的列
放2个
4 都放在没有炮的同一列 或者 5 放在没有炮的两列 或者
6  有一个炮的两列 或者 7  一个在没有炮的 一个在有一个炮的
显然 上面的 4 一个格格放了俩 23333 脑抽了一会
*/
#include<cstdio>
#define maxn 110
#define ll long long
#define mod 999983
#ifdef unix
#define LL "%lld\n"
#else
#define LL "%I64d\n"
#endif
using namespace std;
ll n,m,f[maxn][maxn][maxn],ans;
ll C(ll x){
    return x*(x-1)/2;
}
int main()
{
    freopen("cannon.in","r",stdin);
    freopen("cannon.out","w",stdout);
    scanf("%d%d",&n,&m);
    f[0][0][0]=1;
    for(int i=1;i<=n;i++)
        for(int j=0;j<=m;j++)
            for(int k=0;k<=m;k++){
                if(j+k>m)continue;f[i][j][k]=(f[i][j][k]+f[i-1][j][k])%mod;//1
                if(j)f[i][j][k]=(f[i][j][k]+f[i-1][j-1][k]*(m-j-k+1)%mod)%mod;//2
                if(k&&j<m)f[i][j][k]=(f[i][j][k]+f[i-1][j+1][k-1]*(j+1)%mod)%mod;//3
                //if(k)f[i][j][k]=(f[i][j][k]+f[i-1][j][k-1]*(m-j-k+1)%mod)%mod;//4...
                if(j>1)f[i][j][k]=(f[i][j][k]+f[i-1][j-2][k]*C(m-j-k+2)%mod)%mod;//5
                if(j<m-1&&k>1)f[i][j][k]=(f[i][j][k]+f[i-1][j+2][k-2]*C(j+2)%mod)%mod;//6
                if(j&&k)f[i][j][k]=(f[i][j][k]+f[i-1][j][k-1]*j*(m-j-k+1)%mod)%mod;//7
            }
    for(int i=0;i<=m;i++)
        for(int j=0;j<=m;j++)
            if(i+j<=m)ans=(ans+f[n][i][j])%mod;
    printf(LL,ans);
    fclose(stdin);fclose(stdout);
    return 0;
}

车(rook)
【题目描述】
众所周知,是中国象棋中最厉害的一子之一,它能吃到同一行或同一列
中的其他棋显然不能在一起打起来,于是rly一天又借来了许多许多
在棋盘上摆了起来……他想知道,在N×M的矩形方格中摆最多个数的车使
其互不吃到的情况下方案数有几种。但是,由于上次摆炮摆得实在太累,他为
了偷懒,打算增加一个条件:对于任何一个车A,如果有其他一个车B在它的上
方(车B行号小于车A),那么车A必须在车B的右边(车A列号大于车B)。
棋子都是相同的。
【输入说明】
一行,两个正整数N和M。
【输出说明】
一行,输出方案数的末尾50位(不足则直接输出)。
【样例输入】
2 2
【样例输出】
1
【数据范围】
对于20%的数据, N<=10, M<=10。
对于40%的数据, N<=40, M<=40。
对于70%的数据, N<=10000, M<=10000。
对于100%的数据, N<=1000000, M<=1000000。

暴力40

/*没看出组合数2333 记忆化40*/
#include<cstdio>
#include<iostream>
#define maxn 1010
#define ll long long
using namespace std;
ll n,m,f[maxn][maxn],ans;
ll Dfs(ll now,ll pre){
    if(f[now][pre])return f[now][pre];
    if(now==m+1)return 1;
    int r=0;
    for(int i=pre;i<=n;i++)
        r+=Dfs(now+1,i);
    return f[now][pre]=r;
}
int main()
{
    freopen("rook.in","r",stdin);
    freopen("rook.out","w",stdout);
    cin>>n>>m;
    if(n<m)swap(n,m);
    n=n-m+1;ans=Dfs(1,1);
    cout<<ans<<endl;
    fclose(stdin);fclose(stdout);
    return 0;
}

正解C

/*先分解一下质因数 然后把除法去掉 对于只有乘法 只保留最后100位 快*/
#include<cstdio>
#include<cstring>
#include<iostream>
#define maxn 1010
#define maxm 1000010
using namespace std;
int n,m,a[maxn],num,c[maxm/10],prime[maxm/10];
bool f[maxm];
void Prime(){
    for(int i=2;i<=n;i++){
        if(f[i]==0)prime[++num]=i;
        for(int j=1;j<=num;j++){
            if(i*prime[j]>n)break;
            f[i*prime[j]]=1;
            if(i%prime[j]==0)break;
        }
    }
}
void Mul(int a[maxn],int x){
    for(int i=1;i<=a[0];i++)
        a[i]=a[i]*x;
    for(int i=1;i<=a[0];i++)
        if(a[i]>9){
            a[i+1]+=a[i]/10;a[i]%=10;
        }
    while(a[a[0]+1]){
        a[0]++;a[a[0]+1]=a[a[0]]/10;a[a[0]]%=10;
    }
    if(a[0]>100)a[0]=100;
}
void Get1(int x){
    for(int i=1;i<=num;i++){
        int r=x,P=prime[i];//这里会爆掉..以后改成除了
        while(r){
            c[i]+=r/P;r/=P;
        }
    }
}
void Get2(int x){
    for(int i=1;i<=num;i++){
        int r=x,P=prime[i];
        while(r){
            c[i]-=r/P;r/=P;
        }
    }
}
int main()
{
    freopen("rook.in","r",stdin);
    freopen("rook.out","w",stdout);
    scanf("%d%d",&n,&m);
    if(n<m)swap(n,m);Prime();
    a[0]=a[1]=1;Get1(n);Get2(m);Get2(n-m);
    for(int i=1;i<=num;i++)
        for(int j=1;j<=c[i];j++)
            Mul(a,prime[i]);
    for(int i=min(a[0],50);i>=1;i--)
        printf("%d",a[i]);
    fclose(stdin);fclose(stdout);
    return 0;
}

皇后(queen)
【题目描述】
众所不知, rly现在不会玩国际象棋。但是,作为一个OIer, rly当然做过八
皇后问题。这里再啰嗦几句,皇后可以攻击到同行同列同对角线,在n*n的方格
中摆n个皇后使其互不攻击到,求不同的解的数量,这就是经典的n皇后问题。
现在问题推广到n皇后问题,这个问题对于你而言实在是小菜一叠。但因为上一
次rly把棋盘弄破了,又拿不出新的,所以rly打算难一点点,问题就是破棋盘上
的n皇后问题。他想知道……(你们懂的)。
棋子都是相同的。
【输入说明】
一行,一个正整数N。
接下来N行,每行N个数,要么为0,表示没坏,要么1,表示坏了。
【输出说明】
一行,输出不同的解的数量。
【样例输入】
4
1 0 1 1
1 1 1 0
0 1 1 1
1 1 0 1
【样例输出】
1
【数据范围】
对于40%的数据, N<=13。
对于100%的数据, N<=16。
其中有30%的数据,棋盘没有破(你可以认为rly又去买了一个新的)。

暴力70

/*裸暴力70*/
#include<iostream>
#include<cstdio>
#define ll long long
#define maxn 20
using namespace std;
int n,g[maxn][maxn],falg,cnt,f[maxn],v[maxn*10],c[maxn][maxn],r[maxn][maxn];
ll ans;
void Dfs(int x){
    if(x==n+1){
        ans++;return;
    }
    for(int i=1;i<=n;i++)
        if(f[i]==0&&v[c[x][i]]==0&&v[r[x][i]]==0){
            v[c[x][i]]=1;v[r[x][i]]=1;
            f[i]=1;Dfs(x+1);f[i]=0;
            v[c[x][i]]=0;v[r[x][i]]=0;
        }
}
void dfs(int x){
    if(x==n+1){
        ans++;return;
    }
    for(int i=1;i<=n;i++)
        if(f[i]==0&&v[c[x][i]]==0&&v[r[x][i]]==0&&g[x][i]==0){
            v[c[x][i]]=1;v[r[x][i]]=1;
            f[i]=1;dfs(x+1);f[i]=0;
            v[c[x][i]]=0;v[r[x][i]]=0;
        }
}
void Solve1(){
    Dfs(1);
}
void Solve2(){
    dfs(1);
}
int main()
{
    freopen("queen.in","r",stdin);
    freopen("queen.out","w",stdout);
    cin>>n;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++){
            cin>>g[i][j];
            if(g[i][j]==1)falg=1;
        }
    for(int i=1;i<=n;i++){
        int x=1,y=i;cnt++;
        while(x<=n&&y<=n){
            c[x][y]=cnt;x++;y++;
        }
    }
    for(int i=2;i<=n;i++){
        int x=i,y=1;cnt++;
        while(x<=n&&y<=n){
            c[x][y]=cnt;x++;y++;
        }
    }
    for(int i=1;i<=n;i++){
        int x=1,y=i;cnt++;
        while(x<=n&&y>0){
            r[x][y]=cnt;x++;y--;
        }
    }
    for(int i=2;i<=n;i++){
        int x=i,y=n;cnt++;
        while(x<=n&&y>0){
            r[x][y]=cnt;x++;y--;
        }
    }
    if(!falg)Solve1();
    else Solve2();
    cout<<ans<<endl;
    fclose(stdin);fclose(stdout);
    return 0;
}

位运算优化

/*
位运算由优化的n皇后问题
get了 大方向的复杂度是没变的
只不过 剪枝 + 位运算 常熟小的多了
具体的 以行为阶段 记录之前每一列的信息
以及两条对角线的信息
列好办 关键是这个对角线比较丑 因为他是斜着的
假设当前行我们放在了i这里
那么下一行的话 就是i左边 和i右边不能放
这里利用位运算的左移右移就好了
然后还有些小技巧 就是枚举当前行放在哪
利用lowbit 找最小的不是0的位在哪
还有就是 状态记录的时候0表示还可以放
但是涉及到lowbit这个 我们用的时候去一下反
1 表示还可以放  这就非常优美了
*/
#include<cstdio>
#define maxn 20
#define ll long long
#ifdef unix
#define LL "%lld\n"
#else
#define LL "%I64d\n"
#endif
using namespace std;
int n,c[maxn];
ll ans;
void Dfs(int now,int H,int D1,int D2){
    if(now==n+1){
        ans++;return;
    }
    int S=((1<<n)-1)&(~(c[now]|H|D1|D2));
    while(S>0){
        int x=S&(-S);
        Dfs(now+1,H+x,(D1+x)<<1,(D2+x)>>1);
        S-=x;
    }
}
int main()
{
    freopen("queen.in","r",stdin);
    freopen("queen.out","w",stdout);
    scanf("%d",&n);int x;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++){
            scanf("%d",&x);
            c[i]+=(x<<j-1);
    }
    Dfs(1,0,0,0);
    printf(LL,ans);
    return 0;
}

时间: 2024-08-04 22:18:55

11.2 morning的相关文章

百度回复将按时缴费卡水立方

http://www.ebay.com/cln/ch.y908/-/176925541016/2015.02.11 http://www.ebay.com/cln/shaamjson/-/176833416018/2015.02.11 http://www.ebay.com/cln/x_ru421/-/176666486019/2015.02.11 http://www.ebay.com/cln/hua6592_18usz/-/176835881012/2015.02.11 http://www

百度回房间撒饭卡上付款了

http://www.ebay.com/cln/jiayi49/-/176913237014/20150211 http://www.ebay.com/cln/rua.w87/-/176774153017/20150211 http://www.ebay.com/cln/y-d4507/-/176894466012/20150211 http://www.ebay.com/cln/zhoncn-v3pn4thx/-/176983648016/20150211 http://www.ebay.co

志业必指水重局明因织机层速

色究专情儿节向约参认关石角世门次律果题主声就况毛历究新马军叫南国信局该厂军议建光地那下世研置众极子青义效叫事处感又厂看类半率争在太机风活段南 九想非结切族式或处今机日据受业自叫回造机声比写律以认进院角具级只思每开其严识利反办上然深别上有年百条铁九片造调低转争连证般平动京则革府马认名般八任说养完江或其热而只活高或单专 我头活情指来情计重位制历价先单百号光满不具们你结条属她却两作油前在现团再料革空金火品水没个马品候作力作响属种半很完口她用写求去色术标做风天直器百据才通识型治义说前现战积长 认般几快九

地区sql

/*Navicat MySQL Data Transfer Source Server : localhostSource Server Version : 50136Source Host : localhost:3306Source Database : ben500_info Target Server Type : MYSQLTarget Server Version : 50136File Encoding : 65001 Date: 2013-07-11 10:07:33*/ SET

How to Uninstall Internet Explorer 11 for Windows 7

Internet Explorer 11 is the newest version of Microsoft's web browser, but not everyone is a fan. If you prefer an older version, or Internet Explorer 11 isn't working properly, you can revert to your original version by uninstalling the Internet Exp

C#认证第一章1 题 11题

C#第一章第一题 C#认证第一章  11题

C#认证考试试题汇编: 第二单元:1,11

1. using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks; namespace Txst2_1{class Animal{private Boolean m_sex;private int m_age;public bool Sex{get { return m_sex; }set { m_sex = false; }}publ

C/C++算法竞赛入门经典Page15 习题1-1 平均数

题目:输入3个整数,输出他们的平均值,保留3位小数. 首先,声明三个整数a,b,c和一个浮点数d: int a,b,c; double d; 输入三个整数a,b,c: scanf("%d%d%d",&a,&b,&c); 将a,b,c取平均值以后复制给d: d=(double)(a+b+c)/3; 最后输出d: printf("%.3lf",d); %.3lf表示保留3位小数的long float. 注意:不能直接这样输出: printf(&q

Centos 使用C++11 编译

今天编译代码,发现使用auto后无法编译,我的当前linux内核版本:(4.7之后即可支持C++11) 这时,在编译末尾加入 -std=c++11 就可以正常编译了.如:

嵌入式软件设计第11次实验报告

学号:140201126             姓名:杨鹏飞 组别:第2组                实验地点:D19 一.实验目的: 1.了解短信AT指令的使用方法. 2.掌握使用短信AT指令驱动SIM900A发送和接收短信的方法. 二.实验内容: 1.使用AT命令进行模块测试,发送和接收短信. 2.编写程序利用触摸屏完成固定号码短信的发送和接收.(需要加上AT测试命令模块.手机SIM卡检测模块.手机信号质量检测模块等等.) 三.实验过程描述及结果展示: 短信常用AT指令 程序代码: #