#2208: 一串數字 的分析


morris1028 (碼畜)

學校 : 國立花蓮高級中學
編號 : 3529
來源 : [114.37.59.62]
最後登入時間 :
2021-07-12 19:00:43
d118. 一串數字 | From: [118.160.206.23] | 發表日期 : 2009-07-31 16:48

這是我通過的方式,僅供參考而且不一定是正確的

此題要使用遞迴版的Greedy+優化輸出

除了C/C++ 我想其他的語言應該有點難通過

什麼時遞迴版的Greedy呢?

來舉例一下好了 987645821 6

need=6

首先先找9

後面還有還有8個,所以可以輸出第1個9  need=5

之後找不到 9,跳到下一個數字 8

首先找到第1個 8,後面還有7個可以輸出第1個8 need=4

再來找到第2個 8,但是後面只有 2個,而我卻要除了這個8以外 還要3個 (兩個都是取後面的)

所以我必須從上一個8跟這個8之間取 3-2 個 所以取到 7

之後退回原本的 8 ,但是之後掃到尾吧,沒有發現8 

往下一個數字 7 開始掃,....掃到 2 need=1  掃到1 need=0

大致上是這樣,不過這樣應該是聽不懂的

自己想想看吧

By 想破頭的我 (而且還在AC邊緣...)

 
#2217: Re:一串數字 的分析


nanj0178 (nanj)

學校 : 新北市立板橋高級中學
編號 : 2410
來源 : [1.160.111.12]
最後登入時間 :
2024-03-07 10:38:43
d118. 一串數字 | From: [119.77.169.162] | 發表日期 : 2009-08-01 12:45

太威了!!!!!!!!!!!!!!!

 
#2218: Re:一串數字 的分析


morris1028 (碼畜)

學校 : 國立花蓮高級中學
編號 : 3529
來源 : [114.37.59.62]
最後登入時間 :
2021-07-12 19:00:43
d118. 一串數字 | From: [118.161.217.81] | 發表日期 : 2009-08-01 22:37

提供一下程式碼好了,以及程式碼的說明


#include<stdio.h>
#include<stdlib.h>
#include<string.h>
char s[35867525];
void Greedy (int now,int start,int end,int need)
{
    if(now==-1||need==0) return;
    int a,last=start-1; /*start-1 是可能之間都沒有該數字...*/
    for(a=start;a<=end;a++) /*在之間取需要的個數*/
          if(s[a]-48==now)
             {
                if((end-a)<need) /* 若無法在剩餘的數字中取到足夠的個數 則在上一次出現的位子中取數 */
                   {
                     Greedy (now-1,last+1,a-1,need-(end-a)-1); /*不足的往數字(now-1) 從上一次數字(now)出現的位子 到 這個數(now)之前 取不足的數字*/
                     putchar(now+48); /*退回來之後 輸出 now*/
                     need=end-a; /*需要的個數改變*/
                     last=a; /*紀錄上一次的位子*/
                   }
                else
                   {
                      putchar(now+48);
                      last=a; /*紀錄上一次的位子*/
                      need--; /*需要的個數一直減少*/
                   }  
                if(need==0) return; /*若已經達到目標了 則結束*/
             }
    if(need!=0)  Greedy (now-1,last+1,end,need);
    /* 取了或者根本沒取 需求不足 則從上一次紀錄的地方往結尾去找 下一個數字(now-1)*/
}
main()
{
  int n;
  while(scanf("%s %d",s,&n)==2)
      {
          Greedy (9,0,strlen(s)-1,n);/*先找數字 9*/
          printf("\n");
      }
 return 0;
}

說真的,我其實不是很了解我自己在打什麼(被鬼附身),也不知道這支程式碼是快在哪裡...
不過大致上一定要優化輸出,不然毫無勝算...
如果出題者還想增加更強的測資話...恐怕又要在當機一次了
這個算是什麼演算法呢 ? 看起來不太像Greedy...也不太像是 D&C ...

 
#2223: Re:一串數字 的分析


morris1028 (碼畜)

學校 : 國立花蓮高級中學
編號 : 3529
來源 : [114.37.59.62]
最後登入時間 :
2021-07-12 19:00:43
d118. 一串數字 | From: [118.161.220.235] | 發表日期 : 2009-08-03 22:57

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
char s[35867525];
void Greedy (int now,int start,int end,int need)
{
    if(now==-1||need==0) return;
    int a,last=start-1; /*start-1 是可能之間都沒有該數字...*/
    for(a=start;a<=end;a++) /*在之間取需要的個數*/
          if(s[a]-48==now)
             {
                if((end-a)>=need)
                   {
                      putchar(now+48);
                      last=a; /*紀錄上一次的位子*/
                      need--; /*需要的個數一直減少*/
                      if(need==0) return;
                   }                  
                else /* 若無法在剩餘的數字中取到足夠的個數 則在上一次出現的位子中取數 */
                   {
                     Greedy (now-1,last+1,a-1,need-(end-a)-1); /*不足的往數字(now-1) 從上一次數字(now)出現的位子 到 這個數(now)之前 取不足的數字*/
                     for(a=a;a<=end;a++)/*退回來之後 輸出剩餘的全部*/
                       putchar(s[a]);
                     return;
                   }
             }
    if(need!=0)  Greedy (now-1,last+1,end,need);
    /* 取了或者根本沒取 需求不足 則從上一次紀錄的地方往結尾去找 下一個數字(now-1)*/
}
main()
{
  int n;
  while(scanf("%s %d",s,&n)==2)
      {
          Greedy (9,0,strlen(s)-1,n);/*先找數字 9*/
          printf("\n");
      }
 return 0;
}
這是更新版的作法 ! !
既然不足之後 在上一次出現之間去找數字
那麼剩餘的數必定全部在後面
就直接輸出,以減少IF的判斷 可減少到212 MS 少100MS多吧
 
#5851: Re:一串數字 的分析


rockwyc992 (印章)

學校 : 國立中央大學
編號 : 13741
來源 : [223.141.13.244]
最後登入時間 :
2017-02-27 23:14:02
d118. 一串數字 | From: [114.46.133.240] | 發表日期 : 2011-09-21 23:19

提供一下程式碼好了,以及程式碼的說明


#include
#include
#include
char s[35867525];
void Greedy (int now,int start,int end,int need)
{
    if(now==-1||need==0) return;
    int a,last=start-1; /*start-1 是可能之間都沒有該數字...*/
    for(a=start;a<=end;a++) /*在之間取需要的個數*/
          if(s[a]-48==now)
             {
                if((end-a)                   {
                     Greedy (now-1,last+1,a-1,need-(end-a)-1); /*不足的往數字(now-1) 從上一次數字(now)出現的位子 到 這個數(now)之前 取不足的數字*/
                     putchar(now+48); /*退回來之後 輸出 now*/
                     need=end-a; /*需要的個數改變*/
                     last=a; /*紀錄上一次的位子*/
                   }
                else
                   {
                      putchar(now+48);
                      last=a; /*紀錄上一次的位子*/
                      need--; /*需要的個數一直減少*/
                   }  
                if(need==0) return; /*若已經達到目標了 則結束*/
             }
    if(need!=0)  Greedy (now-1,last+1,end,need);
    /* 取了或者根本沒取 需求不足 則從上一次紀錄的地方往結尾去找 下一個數字(now-1)*/
}
main()
{
  int n;
  while(scanf("%s %d",s,&n)==2)
      {
          Greedy (9,0,strlen(s)-1,n);/*先找數字 9*/
          printf("\n");
      }
 return 0;
}

說真的,我其實不是很了解我自己在打什麼(被鬼附身),也不知道這支程式碼是快在哪裡...
不過大致上一定要優化輸出,不然毫無勝算...
如果出題者還想增加更強的測資話...恐怕又要在當機一次了
這個算是什麼演算法呢 ? 看起來不太像Greedy...也不太像是 D&C ...


剛剛有人教我就做出來了

(畢竟提示我的人事個大神)

適用stack實做的....遇到大的就把小的丟出來大的插入

2xx豪秒就可以過了

這題的正解再下面.....雖然寫的不是很好.....也沒有註解

不過短短的很可愛

就看看吧

 

 #include <stdio.h>
#include <string.h>

char str[50000000];
char ans[50000000];
int top;

int main()
{

    int n;
    int len;
    while(scanf("%s", str) != EOF)
    {
        scanf("%d", &n);
        len = strlen(str);
        top = 1;
        ans[0] = str[0];
        for(int i=1 ; i<len ; i++)
        {
            if(top+len-i <= n)
            {
                for(int j=i ; j<len ; j++)
                {
                    ans[top] = str[j];
                    top++;
                }
                break;
            }
            while(str[i] > ans[top-1])
            {
                top--;
                if(top == 0)
                    break;
                if(top+len-i <= n)
                    break;
            }
            ans[top] = str[i];
            top++;
        }
        if(top > n)
            top = n;
        for(int j=0 ; j<top ; j++)
            putchar(ans[j]);
        puts("");
    }
    return 0;
}

 
#6442: Re:一串數字 的分析


stanley17112000 (Stanley)

學校 : 國立交通大學
編號 : 13580
來源 : [66.253.158.102]
最後登入時間 :
2019-02-16 03:29:47
d118. 一串數字 | From: [203.70.75.200] | 發表日期 : 2012-03-05 22:35

這是我通過的方式,僅供參考而且不一定是正確的

此題要使用遞迴版的Greedy+優化輸出

除了C/C++ 我想其他的語言應該有點難通過

什麼時遞迴版的Greedy呢?

來舉例一下好了 987645821 6

need=6

首先先找9

後面還有還有8個,所以可以輸出第1個9  need=5

之後找不到 9,跳到下一個數字 8

首先找到第1個 8,後面還有7個可以輸出第1個8 need=4

再來找到第2個 8,但是後面只有 2個,而我卻要除了這個8以外 還要3個 (兩個都是取後面的)

所以我必須從上一個8跟這個8之間取 3-2 個 所以取到 7

之後退回原本的 8 ,但是之後掃到尾吧,沒有發現8 

往下一個數字 7 開始掃,....掃到 2 need=1  掃到1 need=0

大致上是這樣,不過這樣應該是聽不懂的

自己想想看吧

By 想破頭的我 (而且還在AC邊緣...)

我想出了一個 O(L) 的方法 ( L 為字串長度 )  只是時間複雜度還是不理想

#include <stdio.h>

#include <string.h>

int pos[10][5000000] , top[10] , ptr[10] , len , N , MAX;

char G[50000001];

int main(){

while ( scanf("%s",G) == 1 ){

scanf("%d",&N);

len = strlen( G ); 

memset( top , 0 , sizeof( top ) );

memset( ptr , 0 , sizeof( ptr ) );

for ( int i = 0 ; i < len ; i++ )

pos[G[i]-'0'][top[G[i]-'0']++] = i;

MAX = -1;

for ( int i = 1 ; i <= N ; i++ ){

bool find = false;

for ( int k = 9 ; k >= 0 && !find; k-- ){

while ( ptr[k] < top[k] && pos[k][ptr[k]] <= MAX ) ptr[k]++;

for (   ; ptr[k] < top[k] ; ptr[k]++ ){

if ( pos[k][ptr[k]] + N - i < len  ){

MAX = pos[k][ptr[k]];

ptr[k]++;

putchar(k+'0');

find = true;

break;

}

else break;

}

}

}

puts("");

}

return 0;

}

 

 
ZeroJudge Forum