1. 程式人生 > >4.7清明考試(完蛋)

4.7清明考試(完蛋)

splay 關於 queue 信息 i++ 標記 所在 getchar 遊戲

T1 消失的數字(number)

Time Limit:1000ms Memory Limit:128MB

題目描述

rsy擁有n個數,這n個數分別是a1,a2,…,an。

後來出現了一個熊孩子zhw,用橡皮擦去了其中若幹個數字,並且打亂了剩下的數字。rsy趕到現場後只剩下了m個數字b1,b2,…,bm,她想知道哪些數字被擦去了。

現在你需要告訴rsy被擦去的n-m個數是什麽。

輸入格式(number.in)

第一行一個數n,第二行n個數ai,表示一開始的數字。

第三行一個數m,第四行m個數bi,表示被擦去後的數字。

輸出格式(number.out)

一行n-m個數,從小到大輸出所有被擦去的數字。

輸入樣例

5

1 3 5 7 8

3

3 5 8

輸出樣例

1 7

數據範圍

對於30%的數據n<=1000,ai與bi都是有序的。

對於60%的數據n<=100000,ai與bi都是有序的。

對於80%的數據n<=100000,ai,bi<=n。

對於100%的數據n<=100000,1<=ai,bi<=10^9。

   (T1)一看題目,這多簡單,數據100000明顯nlog(n)的解法嘛,然後自然想到二分,感覺沒問題了,結果數據太強大(沒考慮全面,沒想到還有相同的數字)考完試後看完標程,恍然大悟,一看這麽簡單啊,不應該啊!!

解:將第二數列中的數從第一個數列中刪除(不輸出就好了),排兩遍順倆數列就都是單調的了,增減看題目,第二個數列下標從1開始碰上與的一個數列有相同的數就不輸出第一個數列中的那個數(相當於刪除了),按順序輸出就好了.(自己zz了)

技術分享圖片
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,m;
int a[100001],b[100001];
int read()
{
    int sum=0,fg=1; char c=getchar();
    while(c>9||c<0){if(c==-)fg=-1;c=getchar();}
    while(c<=9&&c>=0){sum=sum*10+c-0;c=getchar();}
    
return fg*sum; } int main() { // freopen("number.in","r",stdin);freopen("number.out","w",stdout); n=read(); for(int i=1;i<=n;i++)a[i]=read(); sort(a+1,a+1+n); m=read(); for(int i=1;i<=m;i++)b[i]=read(); sort(b+1,b+1+m); int k=1; for(int i=1;i<=n;i++) { if(a[i]==b[k])k++; else cout<<a[i]<<" "; } // fclose(stdin);fclose(stdout); }
修改AC代碼奉上

T2 一道數論好題(math)

Time Limit:1000ms Memory Limit:128MB

題目描述

rsy最近在研究歐幾裏得算法,不會的同學可以去看下課件以及代碼……

現在她想到了一個新的問題,求k個數的最大公約數!

事實上這個問題仍然很簡單。所以rsy想強化一下,她覺得最大公約數等於1就不是很有趣了。因此她想在n個數中找最多的數,使得它們的最大公約數不等於1。

現在rsy想知道,能找最多多少個數。

輸入格式(math.in)

第一行一個數n。

第二行n個數ai。

輸出格式(math.out)

一個數表示答案。

輸入樣例

5

2 3 4 5 6

輸出樣例

3

數據範圍

對於30%的數據n<=5。

對於50%的數據n<=20。

對於80%的數據n<=1000,ai<=1000。

對於100%的數據1<=n<=100000,1<=ai<=100000,數據幾乎是隨機的。

一看求最大公約數,正解,不會,求個gcd吧,數據這麽大,這咋挑數呢?沒辦法寫個dfs,再優化優化,應該大約可以過個50%的數據吧,

結果只過了30%。

 30%--直接dfs;

50%-80%--桶排的話應該可以過,數的大小<=1000,比較密集。

100%,看起來既得部分分還簡單,開始記錄一下每一個數出現的次數,枚舉這一堆數的最大公約數,既然這些數最大公約數不唯一那另外的一些數一定是這個約數的倍數,二重循環記錄每個數的個數總和,比較得出一個max就可以啦。

技術分享圖片
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,m,ans,maxn;
int a[2000001];
int read()
{
    int sum=0,fg=1; char c=getchar();
    while(c>9||c<0){if(c==-)fg=-1;c=getchar();}
    while(c<=9&&c>=0){sum=sum*10+c-0;c=getchar();}
    return fg*sum;
}
int main()
{
//    freopen("math.in","r",stdin);freopen("math.out","w",stdout);
    n=read();
    int x;
    for(int i=1;i<=n;i++)
    {
        x=read();
        a[x]++;
        maxn=max(maxn,x);
    }
    for(int i=2;i<=maxn;i++)
    {
        int sum=0;
        for(int j=i;j<=maxn;j+=i)
        {
            sum+=a[j];
        }
        ans=max(ans,sum);
    }
    printf("%d",ans);
//    fclose(stdin);fclose(stdout);
}
AC代碼奉上

T3 掃雷(mine)

Time Limit:1000ms Memory Limit:128MB

題目描述

rsy最近沈迷於一款叫掃雷的遊戲。

這個遊戲是這樣的。一開始網格上有n*m個位置,其中有一些位置有雷。每次rsy可以左鍵點擊一個方塊,此時若這個方塊是雷,則rsy被炸,遊戲結束,否則如果這個位置周圍8格有x個雷,則會顯示數字x。特別地,當x=0時,系統會自動左鍵點擊附近8個位置。(此時附近8個位置一定沒有雷,假如附近8個位置仍存在x=0,則繼續往外擴展)想要更進一步獲得關於題目的信息,打開程序->附近->遊戲->掃雷或者直接打開下發的可執行文件。

或者rsy右鍵點擊一個位置,標註這個位置是雷。

不幸的是,她鼠標不能左右鍵同時點擊,因此只需考慮她左鍵點擊與右鍵點擊就可以了。

註意遊戲勝利的條件是所有非雷的位置都被左鍵點擊到。(特別地,當一開始時n*m個位置都是雷時,LYK自動獲得勝利)

rsy從網上下載了金手指,很輕易地就掌握了所有雷所在的位置。rsy想通過最少的點擊次數獲得勝利(這裏的點擊次數不包括系統自動點擊)。於是他來請求你的幫助。

輸入格式(mine.in)

第一行兩個數n,m。

接下來n行,每行m個數ai,j,表示這個矩陣。若ai,j=’*’則表示這個位置是雷,若ai,j=’.’則表示不是雷。

輸出格式(mine.out)

一個數表示答案。

輸入樣例

3 3

..*

...

..*

輸出樣例

2

對於30%的數據n=1;

對於另外20%的數據n,m<=3;

對於再另外20%的數據*大致占矩陣的2/3且數據隨機。

對於100%的數據n,m<=1000。

Hint:

適度遊戲益腦,沈迷遊戲傷身。

解:既然可以自動擴展,明顯bfs啊,又要點擊次數最小,那肯定要先點可以擴展的絕對比點不能擴展的更優,開個數組記錄下,兩重循環bfs,擴展到的記錄下來,最後圖中還有一些個點沒有被標記過並且不是雷的需要單點,每點一個次數加1,加完以後就是最少的次數了。so easy!

技術分享圖片
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
int n,m,ans;
int dx[9]={0,0,1,1,1,-1,-1,-1};
int dy[9]={-1,1,0,-1,1,0,-1,1};
char a[1005][1005];        //數組[1001]完蛋 
int map[1005][1005];
struct ahah{
    int x,y;
}cur,str,kpl;
int read()
{
    int sum=0,fg=1; char c=getchar();
    while(c>9||c<0)
    {
        if(c==-)fg=-1;
        c=getchar();
    }
    while(c<=9&&c>=0)
    {
        sum=sum*10+c-0;
        c=getchar();
    }
    return fg*sum;
}
queue <ahah> que;
bool vis[1005][1005];
void bfs(int x,int y)
{
    kpl.x=x;kpl.y=y;
    vis[x][y]=1;
    que.push(kpl);
    while(!que.empty())
    {
        str=que.front();
        que.pop();
        for(int i=0;i<8;i++)
        {
            cur.x=str.x+dx[i];
            cur.y=str.y+dy[i];
            if(cur.x>=1&&cur.x<=n&&cur.y>=1&&cur.y<=m&&!vis[cur.x][cur.y]&&a[cur.x][cur.y]!=*)
            {
                vis[cur.x][cur.y]=1;
                if(map[cur.x][cur.y]==0)que.push(cur); 
            }
        }
    } 
}
int main()
{
//    freopen("mine.in","r",stdin);freopen("mine.out","w",stdout);
    n=read();m=read();
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            cin>>a[i][j];
            if(a[i][j]==*)
            {
                map[i][j-1]++;
                map[i][j+1]++;
                map[i+1][j]++;
                map[i-1][j]++;
                map[i+1][j+1]++;
                map[i+1][j-1]++;
                map[i-1][j+1]++;
                map[i-1][j-1]++;
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(map[i][j]==0&&!vis[i][j]&&a[i][j]!=*)
            {
                bfs(i,j);
                ans++;        
            }
        }
    }

    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(!vis[i][j]&&a[i][j]!=*)ans++;
        }
    }
    printf("%d",ans);
//    fclose(stdin);fclose(stdout);
}
//附上組數據 
/*
輸入: 
1 16
...*....*.*.*.*.

輸出:6 
*/
AC代碼奉上

總結:

對於這類模擬來說,越簡單就越容易忽視一些細節,做題不細心,題目中的條件要看全面,數組不能卡數據大小盡量多大個一二百的,做題思路要開闊避免慣性思維,開闊思路。

到的記錄下來,最後圖中還有一些個點沒有被標記過並且不是雷的需要單點,每點一個次數加1,加完以後就是最少的次數了。

致謝君之垂幸。

4.7清明考試(完蛋)