1. 程式人生 > >17.8.17第八次測試

17.8.17第八次測試

code mod pen tar 測試 str 時間 div rain

1. 鼎紋

技術分享
【問題描述】
據說鼎紋圖案的制造是銅模印出來的,這是我國古代勞動人民智慧的結晶。銅模印過的地方,會留下深深的印記,經過時間的煉化,洗練成歷史的遺存。
聰明的古代勞動人民擁有一個 a 行 b 列的銅模,每個位置要麽是 0(代表
這個點是平的),要麽是 1(代表這個點是凸起的)。他們想造 個 n 行 m 列的鼎 ,其中每個位置也都是 01,表示經過若幹次印後,每個位置的結果。
有一些要求。銅模是不能旋轉和翻轉的;在印的過程當中,銅模的凸起不
能出現在鼎面的外面(平的部分是可以出現在外面的),鼎面上的同一個位置不能被多個凸起印下(在任意兩次印時,鼎面上不存在一個點,使得這兩次都有銅模上為 
1 的點覆蓋它)。 請你判斷這個鼎面能不能被印出來。 輸入文件件名為 grain.in。 本題多測。 第一行,一個整數 T ,表示測試 點數量。接下來 T 個測試點,每 個測試點中: 第一行包含 4 個整數 n,m,a,b。 接下來 n 行 ,每行 m 個字符,描述鼎面 。“0”表示 平,“1”表示凸起。接下來 a 行,每行 b 個字符, 描述銅模。“0”表示平,“1”表示凸起。 輸出文件名為 grain.out。 共有 T 行 ,對於每個測試點,輸出 “YES”(能)或“NO”(不能)。 測試數據: grain.in 2 3 4 4 2 1100 0110 1100 10 01 10 00 2 2 2 2 11 11
01 10 grain.out YES NO 對於 70% 的數據,n,m,a, b <= 50。 對於 100% 的數據,1 <= T <=10; 1<=n,m, a, b <= 1000
View Code

題解:大模擬啊這題,沒啥特別的算法。輸入模板的時候存下來每一個點和模板最左上角那個點的相對位置,然後遍歷鼎面,如果為1,就從這點開始,把和它相對位置和之前模板相對位置一樣的點全部置為0,若超出邊界或者已經為0什麽的就輸出no,若遍歷完成就是yes。

技術分享
#include<cstdio>
#include<cstring>
#include<algorithm>
using
namespace std; struct kk{ int x,y; }k[100010]; char tar[1005][1005]; int n,m,a,b,t,s,tx,ty,sx,sy; char g; int main(){ freopen("grain.in","r",stdin); freopen("grain.out","w",stdout); scanf("%d",&t); while(t--){ int flg=1,cnt=0,ff=1; scanf("%d%d%d%d",&n,&m,&a,&b); for(int i=0;i<n;i++) for(int j=0;j<m;j++) tar[i][j]=0; for(int i=1;i<=a;i++) for(int j=1;j<=b;j++) tar[i][j]=0; for(int i=0;i<n;i++) scanf(" %s",&tar[i]); for(int i=1;i<=a;i++) for(int j=1;j<=b;j++){ scanf(" %1d",&s); if(s){ if(ff==1){ k[++cnt].x=0; k[cnt].y=0; sx=i; sy=j; ff=0; } else{ k[++cnt].x=i-sx; k[cnt].y=j-sy; } } } for(int i=0;i<n;i++){ if(flg==0)break; for(int j=0;j<m;j++){ if(flg==0)break; if(tar[i][j]==1){ if(ff==1){ flg=0; break; } for(int p=1;p<=cnt;p++){ tx=i+k[p].x,ty=j+k[p].y; char e=tar[tx][ty]; if(tx>=0&&ty>=0&&tx<n&&ty<m&&(e==1)){ tar[tx][ty]=0; } else{ flg=0; break; } } } } } if(flg)printf("YES\n"); else printf("NO\n"); } return 0; }
View Code

2. 看球賽

技術分享
2200 年 裏奧迪奧帶領的十星巴西對戰萊昂納多帶領的阿根廷的世界杯決賽馬上開始了!前來在巨型球場觀看比賽的觀眾數不甚數,但是由於突如其來的系統原因,大家不能網上購票,只能到售票窗口,排成長龍買票. 按售票處規定,每一個限購一張門票,且每一張門票 50 美元。 在排成長龍的球迷中有 n 個人手持 50 美元,另外有 n 個人手持 100 美元。假設售票處開始的時候沒有零錢,試問這 2n 個球迷有多少種排隊方式使得售票處不會出現找不出錢的尷尬局面,導致拖延球迷看球時間。
【輸入與輸出說明】
輸入兩行,第一行一個正整數 T,表示數據個數。
第二行有 T 個正整數,n1,n2,....nT. 輸出 T 行,每一行為被 10^9+7 模過的結果。
【樣例輸入】 【樣例輸出】
1                  2
2

2                  2
2  5              42

【樣例說明】
例如當 n=2 時,用 A 表示手持面值 50 美元的球迷,用 B 表示手持面值為 100 美元的球迷,則最多可得到以下兩組不同的排隊方式使得售票處不會出現找不出錢的情況。
售票處 A A B B
售票處 A B A B
【數據範圍】
對於 10% n <= 10, T <= 10
對於 20% n <= 15, T <= 10
對於 60% n <= 2000, T <= 10
對於其中 20% 2000 < n <= 10^7, T <= 3
對於其中 20% 10^7 < n <= 3*10^7, T = 1
View Code

題解:一道數學題。要用卡特蘭數的相關知識。當時不會,所以沒做出來。

卡特蘭數:

卡特蘭數又稱卡塔蘭數,英文名Catalan number,是組合數學中一個常出現在各種計數問題中出現的數列。以比利時的數學家歐仁·查理·卡塔蘭 (1814–1894)的名字來命名,其前幾項為 : 1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, 208012, 742900, 2674440, 9694845, 35357670, 129644790, 477638700, 1767263190, 6564120420, 24466267020, 91482563640, 343059613650, 1289904147324, 4861946401452, ...

令h(0)=1,h(1)=1,catalan數滿足遞推式 : h(n)= h(0)*h(n-1)+h(1)*h(n-2) + ... + h(n-1)*h(0) (n>=2) 例如:h(2)=h(0)*h(1)+h(1)*h(0)=1*1+1*1=2 h(3)=h(0)*h(2)+h(1)*h(1)+h(2)*h(0)=1*2+1*1+2*1=5 另類遞推: h(n)=h(n-1)*(4*n-2)/(n+1); 遞推關系的解為: h(n)=C(2n,n)/(n+1) (n=0,1,2,...) 遞推關系的另類解為: h(n)=c(2n,n)-c(2n,n-1)(n=0,1,2,...) 以上來自百度百科。 知乎上有一個對公式推導的文覺得不錯,可以看看。 https://www.zhihu.com/question/60677340 沒有授權,侵刪。 上代碼: 技術分享
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define mod 1000000007
#define ll long long
ll ans,n,s1,s2,map[10010],m;
int t;

ll ksm(ll a,ll b){
    ll ret=1,x=a;
    while(b){
        if(b&1)ret=1ll*ret*x%mod;
        x=x*x%mod;
        b>>=1;
    }
    return ret;
}

int main(){
    freopen("football.in","r",stdin);
    freopen("football.out","w",stdout);
    scanf("%d",&t);
    while(t--){
        scanf("%I64d",&n);
        m=n<<1;
        s1=s2=1;
        for(int i=1;i<=n;++i){
            s1=s1*(m-i+1)%mod;
            s2=s2*i%mod;
        }
        s2=s2*(n+1)%mod;
        ans=s1*ksm(s2,mod-2)%mod;
        printf("%I64d\n",ans);
    }
}
View Code

3.靶形數獨

技術分享
【題目描述】
小城和小華都是熱愛數學的好學生,最近,他們不約而同地迷上了數獨遊戲,好勝的他們想用數獨來一比高低。但普通的數獨對他們來說都過於簡單了,於是他們向 Z 博士請教,Z 博士拿出了他最近發明的“靶形數獨”,作為這兩個孩子比試的題目。
靶形數獨的方格同普通數獨一樣,在 9 格寬×9 格高的大九宮格中有 93 格寬×3 格高的小九宮格(用粗黑色線隔開的)。在這個大九宮格中,有一些數字是已知的,根據這些數字,利用邏輯推理,在其他的空格上填入 19 的數字。每個數字在每個小九宮格內不能重復出現,每個數字在每行、每列也不能重復出現。但靶形數獨有一點和普通數獨不同,即每一個方格都有一個分值,而且如同一個靶子一樣,離中心越近則分值越高。
上圖具體的分值分布是:最裏面一格(黃色區域)為 10 分,黃色區域外面的一圈(紅色區域)每個格子為 9 分,再外面一圈(藍色區域)每個格子為 8 分,藍色區域外面一圈(棕色區域)每個格子為 7 分,最外面一圈(白色區域)每個格子為 6 分,如上圖所示。比賽的要求是:每個人必須完成一個給定的數獨(每個給定數獨可能有不同的填法),而且要爭取更高的總分數。而這個總分數即每個方格上的分值和完成這個數獨時填在相應格上的數字的乘積的總和。如圖,在以下的這個已經填完數字的靶形數獨遊戲中,總分數為 2829。遊戲規定,將以總分數的高低決出勝負。
由於求勝心切,小城找到了善於編程的你,讓你幫他求出,對於給定的靶形數獨,能夠得到的最高分數。
View Code

技術分享

技術分享
【輸入描述】
一共 9 行。每行 9 個整數(每個數都在 09 的範圍內),表示一個尚未填滿的數獨方
格,未填的空格用“0”表示。每兩個數字之間用一個空格隔開。
【輸出描述 】
輸出可以得到的靶形數獨的最高分數。如果這個數獨無解,則輸出整數-1。
【樣例輸入 】
【輸入輸出樣例 17 0 0 9 0 0 0 0 1
1 0 0 0 0 5 9 0 0
0 0 0 2 0 0 0 8 0
0 0 5 0 2 0 0 0 3
0 0 0 0 0 0 6 4 8
4 1 3 0 0 0 0 0 0
0 0 7 0 0 2 0 9 0
2 0 1 0 6 0 8 0 4
0 8 0 5 0 4 0 1 2
【輸入輸出樣例 12829
【輸入輸出樣例 20 0 0 7 0 2 4 5 3
9 0 0 0 0 8 0 0 0
7 4 0 0 0 5 0 1 0
1 9 5 0 8 0 0 0 0
0 7 0 0 0 0 0 2 5
0 3 0 5 7 9 1 0 8
0 0 0 6 0 1 0 0 0
0 6 0 9 0 0 0 0 1
0 0 0 0 0 0 0 0 6
【輸入輸出樣例 22852
【數據範圍】
40%的數據,數獨中非 0 數的個數不少於 3080%的數據,數獨中非 0 數的個數不少於 26100%的數據,數獨中非 0 數的個數不少於 24
View Code

題解:和八皇後很像的一道,因為時間4s,所以可以暴力搜索,也沒啥技術含量,完全考暴力。遍歷每個點可能情況,若填滿就更新得分就行。

代碼:

技術分享
#include<cstdio>
#include<cstring>
#include<algorithm>
#define searchnext(x,y) y==9? search(x+1,1):search(x,y+1)
using namespace std;
int get[11][11][11];
bool r[10][10],l[10][10],s[10][10];
int a[10][10],b[10][10];
int ans=-1,sum;
int cul(int x,int y,int k)
{
    if(x==5&&y==5)return 10*k;
    else if(x>=4&&x<=6&&y>=4&&y<=6)return 9*k;
    else if(x>=3&&x<=7&&y>=3&&y<=7)return 8*k;
    else if(x>=2&&x<=8&&y>=2&&y<=8)return 7*k;
    else return 6*k;
}

bool fill(int x,int y,int k){
    if(r[x][k]||l[y][k]||s[(x-1)/3*3+(y-1)/3][k])return 0;
    b[x][y]=k;
    r[x][k]=l[y][k]=s[(x-1)/3*3+(y-1)/3][k]=1;
    sum+=get[x][y][k];
    return 1;
}

void del(int x,int y,int k)
{
    r[x][k]=l[y][k]=s[(x-1)/3*3+(y-1)/3][k]=0;
}

void search(int x,int y){
    if(x==10){
        ans=max(ans,sum);
        return;
    }
    if(b[x][y])searchnext(x,y);
    else 
    {
    for(int i=1;i<=9;i++)
    {
        int t=sum;
        if(fill(x,y,i))
        {
            searchnext(x,y);
            del(x,y,i);
            sum=t;
        }
    }
    b[x][y]=0;
    }
}

int main(){
    freopen("sudoku.in","r",stdin);
    freopen("sudoku.out","w",stdout);
    for(int i=1;i<=9;i++)
       for(int j=1;j<=9;j++)
          for(int k=1;k<=9;k++)
             get[i][j][k]=cul(i,j,k);
    for(int i=9;i>0;i--)
        for(int j=9;j>0;j--){
            scanf("%d",&a[i][j]);
            if(a[i][j])fill(i,j,a[i][j]);
        }
    search(1,1);
    printf("%d",ans);
    return 0;
}
View Code

17.8.17第八次測試