NOIP2008解題報告

來源:互聯網
上載者:User

標籤:style   blog   http   color   os   io   資料   for   

2008年的題目相對比較簡單,都不是很麻煩,認真寫就能寫對。

 

第一題:

題目大意:給出一個小寫單詞,求出最少出現的字母的出現次數和最多出現的字母的出現次數。

 

解題過程:直接hash類比就好。

 

第二題:

給你n根火柴棍,你可以拼出多少個形如“A+B=C”的等式?等式中的A、B、C是用火柴棍拼出的整數(若該數非零,則最高位不能是0)。用火柴棍拼數字0-9的拼法:

注意:

1. 加號與等號各自需要兩根火柴棍

2. 如果A≠B,則A+B=C與B+A=C視為不同的等式(A、B、C>=0)

3. n根火柴棍必須全部用上。n<=24

 

解題過程:

1.一開始看到A+B=C,想到直接枚舉,但是也有可能出現1111+0=1111的情況。。因此不好確定枚舉的範圍。

2.於是決定用dfs兩個加數,然後看剩下的火柴能否拼出和。對於任意一個數,可以在它的末尾加上0~9的數字,代價是相應需要的火柴數量,這樣保證不會重複。有個小最佳化,不過我懶得寫了,就是令第一個數不比第二個數大,搜到結果時,如果第一個數和第二個數相等,ans+1,否則ans+2。這樣可以減少一半的搜尋量,不過資料如此小,不寫也無所謂。

 

第三題:

題目大意:就是方格取數的變形,變成了2個人一起走,且另外一個人走過的地方不能再走。

解題過程:

和2000年方格取數那題幾乎一樣。只不過00年的是走過的地方可以再走,只不過得到的分數為0,因此只要在00年那題的動態規劃方程裡改一下,如果i=j且沒有到達終點的時候,F[k][i][j]=-inf. F[k][i][j]表示走了k步,第一個人向下走了i步,第二個人向下走了j步的最大得分。

動態規劃的部分代碼:

 1     for (int k=1;k<=n+m-2;k++) 2         for (int i=0;i<n;i++) 3             for (int j=0;j<n;j++) 4             { 5                 if (i==j&&k!=n+m-2) 6                 { 7                     g[k][i][j]=-210000000; 8                     continue; 9                 }10                 if (i!=0 && j!=0)11                     g[k][i][j]=ma(g[k][i][j],g[k-1][i-1][j-1]);12                 if (i!=0 && j!=k)13                     g[k][i][j]=ma(g[k][i][j],g[k-1][i-1][j]);14                 if (i!=k && j!=k)15                     g[k][i][j]=ma(g[k][i][j],g[k-1][i][j]);16                 if (i!=k && j!=0)17                     g[k][i][j]=ma(g[k][i][j],g[k-1][i][j-1]);18                 g[k][i][j]+=a[i+1][1+k-i]+a[j+1][1+k-j];19             }


第四題:

Tom最近在研究一個有趣的排序問題。,通過2個棧S1和S2,Tom希望藉助以下4種操作實現將輸入序列升序排序。

操作a

如果輸入序列不為空白,將第一個元素壓入棧S1

操作b

如果棧S1不為空白,將S1棧頂元素彈出至輸出序列

操作c

如果輸入序列不為空白,將第一個元素壓入棧S2

操作d

如果棧S2不為空白,將S2棧頂元素彈出至輸出序列

如果一個1~n的排列P可以通過一系列操作使得輸出序列為1,2,…,(n-1),n,Tom就稱P是一個“可雙棧排序排列”。例如(1,3,2,4)就是一個“可雙棧排序序列”,而(2,3,4,1)不是。描述了一個將(1,3,2,4)排序的操作序列:<a,c,c,b,a,d,d,b>

當然,這樣的操作序列有可能有幾個,對於上例(1,3,2,4),<a,c,c,b,a,d,d,b>是另外一個可行的操作序列。Tom希望知道其中字典序最小的操作序列是什麼。

 

解題過程:

1.一開始手工類比了一下,感覺可以貪心。如果當前元素比棧頂元素大,那麼肯定不能放到棧頂。(有點類似漢諾塔。)貪心策略如下:能往A棧放的就盡量往A棧放,否則放B棧,如果兩個都沒法放,就輸出無解。如果當前元素就是下一個要到輸出隊列的元素,那麼進棧A然後出來,也就是操作’a‘+’b‘,然後用一個while把該出來的都出來。。很快寫好,自己寫棧也才1000b左右,但是提交只能過5個點。。考試來不及這樣寫也不錯。。

2.正解:參考部落格http://blog.csdn.net/kqzxcmh/article/details/9566813 寫的非常清晰,代碼也簡潔易懂,短小精悍。。

首先根據棧的性質,S[i],S[j]兩個元素不能進入同一個棧 <=> 存在k,滿足i<j<k,使得S[k]<S[i]<S[j]. 不會證明,但絕對正確。。簡單點說,就是對於入棧序列的某個元素,在它前面的且比它大的元素必須是遞增的(從右往左看遞增,從左往右遞減。)這樣好理解,但是編程時還是用存在k,滿足i<j<k,使得S[k]<S[i]<S[j]. 來寫。

因此只要找出所有不能在同時在同一個棧的入棧序列出現的數對(i,j),讓前面的元素盡量進A棧。這實際上是一個判斷二分圖的過程,用染色的方法判斷,如果不是二分圖必然無解。如果是,類比出棧即可。

My Code:

 1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4  5 char ans[2014]; 6 int n,a[1010],stack1[1010],stack2[1010],top1,top2,cur; 7 int p[1010],q[1010]; 8 int g[1010],color[1010],edge[1010][1010],flag=1; 9 10 void pop()11 {12     while (stack1[top1]==cur||stack2[top2]==cur)13     {14         if (stack1[top1]==cur)15         {16             cur++;17             top1--;18             printf("b ");19         }20         else21         {22             cur++;23             top2--;24             printf("d ");25         }26     }27 }28 29 void dfs(int x,int c)30 {31     if (!flag)32         return;33     color[x]=c;34     for (int i=1;i<=n;i++)35         if (edge[x][i])36         {37             if (color[i]==c)38             {39                 flag=0;40                 return;41             }42             if (!color[i])43                 dfs(i,3-c);44         }45 }46 47 void solve()48 {49      g[n+1]=210000;50      for (int i=n;i>=1;i--)51          g[i]=a[i]<g[i+1]? a[i]:g[i+1];52      for (int i=1;i<n;i++)53           for (int j=i+1;j<=n;j++)54               if (a[i]<a[j]&&g[j+1]<a[i])55                   edge[i][j]=edge[j][i]=1;56      for (int i=1;i<=n;i++)57          if (!color[i])58              dfs(i,1);59      if (!flag)60      {61          cout<<0<<endl;62          return;63      }64      cur=1;65      stack1[0]=stack2[0]=210000;66      for (int i=1;i<=n;i++)67      {68           if (color[i]==1)69          {70             printf("a ");71             stack1[++top1]=a[i];72          }73          else74          {75              printf("c ");76              stack2[++top2]=a[i];77          }78          pop();79      }80      pop();81 }82 83 int main()84 {85     //freopen("in.txt","r",stdin);86     //freopen("out.txt","w",stdout);87     cin >> n;88     for (int i=1;i<=n;i++)89         scanf("%d",&a[i]);90     solve();91     return 0;92 } 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.