2009年12月25日

          TopCoder SRM 403 Level2 1000
          4和7是幸運數字,如果一個數只包含4和7,那么這個數字也是一個幸運數字
          給定一個1-1,000,000的數字,求這個數字是否可以僅由幸運數字相加得出,返回所有的幸運數字加數,如果有多組解,返回加數最少的一組

          以前沒有遇到過這樣的DP題目
          這題加深了我對于“每個子問題的答案都是最佳答案”的理解
          首先是額外的計算
          將范圍以內的幸運數字打表
          然后從輸入數字N開始遞減DP計算
          N的步數為0
          如果最后0的步數為正數
          說明有解
          再從0開始遞增尋找解的路徑

          不過這個方法最后也沒有通過tc的系統測試
          數字一大就超時了
          后面又時間再研究一下
          看看有沒有辦法在改進

           1 import java.util.*;
           2 import java.util.regex.*;
           3 import java.text.*;
           4 import java.math.*;
           5 import java.awt.geom.*;
           6 
           7 public class TheSumOfLuckyNumbers
           8 {
           9     
          10     public int[] sum(int n)
          11     {
          12         ArrayList<Integer> table = calTable();
          13         int[] dp = new int[n+1];
          14         Arrays.fill(dp, Integer.MAX_VALUE-10);
          15         dp[n] = 0;
          16         int i , j;
          17         for(i = n; i > 0 ; -- i){
          18             for(int lucky:table){
          19                 if(i - lucky >=0 && dp[i] + 1 < dp[i - lucky])
          20                     dp[i - lucky] = dp[i] + 1;
          21             }
          22         }
          23         if(dp[0== Integer.MAX_VALUE)
          24             return new int[0];
          25         ArrayList<Integer> ans = new ArrayList<Integer>();
          26         int total = dp[0]-1;
          27         for(i = 0 ; i <= n; ++ i){
          28             for(int lucky:table){
          29                 if(i + lucky <= n && dp[i + lucky] == total){
          30                     ans.add(lucky);
          31                     i += lucky-1;
          32                     total--;
          33                     break;
          34                 }
          35             }
          36         }
          37         int[] ret = new int[ans.size()];
          38         for(i = 0 ; i < ans.size(); ++ i)
          39             ret[i] = ans.get(i);
          40         return ret;
          41     }
          42     
          43 
          44     
          45     public ArrayList<Integer> calTable(){
          46         ArrayList<Integer> table = new ArrayList<Integer>();
          47         table.add(4);
          48         table.add(7);
          49         int i = 1;
          50         while(i < 7){
          51             ArrayList<Integer> temp = new ArrayList<Integer>();
          52             for(int j = 0 ; j < table.size(); ++ j){
          53                 int newItem = table.get(j) * 10;
          54                 
          55                 temp.add(newItem+4);
          56                 temp.add(newItem+7);
          57             }
          58             i++;
          59             table.addAll(temp);
          60         }
          61         return table;
          62     }
          63 }


          posted @ 2009-12-25 16:13 jav7er 閱讀(167) | 評論 (0)編輯 收藏
           
          TopCoder SRM 405 Level 2 1000
          一個理想的字符串,其中每個字母第一次出現的位置N,與這個字母在字符串中出現的次數M是相等的,求給定長度的字符串中最小的一個理想字符串

          字符串長度小于100
          相當于去搜索1~100中的一組不同的數
          加起來等于長度L
          同時每個數字都要小于等于比自己小的所有數的和加一
          因為L比較小
          所以用深搜就可以了
          在這個過程中要注意深搜時候需要從大往小搜
          這樣才能滿足“最小的”結果
          搜索完之后的字符串構建的步驟因為StringBuffer用的不熟練
          反而調試了很久
           1 import java.util.*;
           2 import java.util.regex.*;
           3 import java.text.*;
           4 import java.math.*;
           5 import java.awt.geom.*;
           6 
           7 public class IdealString
           8 {
           9     int[] table = new int[26];
          10     int finalindex = 0;
          11     int L;
          12     
          13     public String construct(int length)
          14     {
          15         Arrays.fill(table, 0);
          16         L = length;
          17         if(dfs(100)){
          18             StringBuffer sb = new StringBuffer();
          19             char c = 'A';
          20             int i , j = 0;
          21             for(i = 0 ; i < L; ++ i)
          22                 sb.append(' ');
          23             for(i = 0 ; i < finalindex; ++i){
          24                 sb.setCharAt(table[i] - 1, c ++);
          25                 table[i]--;
          26             }
          27             for(i = 0 ; i < L; ++ i){
          28                 if(sb.charAt(i) != ' ')
          29                     continue;
          30                 while(table[j] == 0) j++;
          31                 sb.setCharAt(i, (char)('A' + j));
          32                 table[j]--;
          33             }
          34             return sb.toString();
          35         }
          36         return new String();
          37     }
          38     
          39     boolean dfs(int num, int index, int sum){
          40         table[index] = num;
          41         int base = num + sum;
          42         if(base == L){
          43             table[index] = num;
          44             finalindex = index + 1;
          45             return true;
          46         }
          47         if(base > L)
          48             return false;
          49         int total = 0;
          50         for(int i = 0 ; i <= index ; ++ i)
          51             total += table[i];
          52         for(int i = total + 1;  i >= num + 1-- i){            
          53             if(base + i <= L && dfs(i, index +1, base))
          54                 return true;
          55         }
          56         return false;
          57     }
          58 }


          posted @ 2009-12-25 16:00 jav7er 閱讀(143) | 評論 (0)編輯 收藏

          2009年12月16日

          TopCoder SRM 399 Level 2 1000
          http://www.topcoder.com/stat?c=problem_statement&pm=8758&rd=12171
          給定N和一個整數集合a,用不屬于a的3個整數相乘得出離N最近的整數

          N的范圍1~1000
          從小到大3重循環就可以解
          理論上的復雜度高達1000^3
          如果確實算一次我的電腦要跑到6秒
          不過其實當乘積減去N已經超過之前的差額時就可以break了
          所以計算量其實很小
          加上break算一次只要零點零幾秒
          另外的陷阱是循環如果只是1~1000是不行的
          有可能會用到比1000還大的因子
           1import java.util.*;
           2import java.util.regex.*;
           3import java.text.*;
           4import java.math.*;
           5import java.awt.geom.*;
           6
           7public class AvoidingProduct
           8{
           9    int SIZE = 1101;
          10    
          11    public int[] getTriple(int[] a, int n)
          12    {
          13        boolean[] table = new boolean[SIZE];
          14        Arrays.fill(table, true);
          15        for(int i = 0  ; i < a.length ; ++ i)
          16            table[a[i]] = false;
          17        int x,y,z;
          18        int[] ans = new int[3];
          19        Arrays.fill(ans, Integer.MAX_VALUE);
          20        int gap = Integer.MAX_VALUE;
          21        Outer:
          22        for(x = 1 ; x < SIZE; ++ x){
          23            if(table[x] == falsecontinue;
          24            for(y = 1; y < SIZE; ++ y){
          25                if(table[y] == falsecontinue;
          26                for(z = 1 ; z < SIZE; ++ z){
          27                    if(table[z] == falsecontinue;
          28                    int total = x * y * z;
          29                    int sub = n - total;
          30                    if(Math.abs(sub) < gap){
          31                        ans[0= x; ans[1= y; ans[2= z;
          32                        gap = Math.abs(sub);
          33                    }

          34                    if(sub < 0 && Math.abs(sub) >= gap)
          35                        break ;
          36                }

          37            }

          38        }

          39        return ans;
          40    }

          41    
          42}
          posted @ 2009-12-16 21:58 jav7er 閱讀(127) | 評論 (0)編輯 收藏

          2009年12月15日

          TopCoder SRM 397 Level2 1000
          http://www.topcoder.com/stat?c=problem_statement&pm=8746
          一個彩球集合,重量各不相同,給定容器大小如何帶回盡量多的彩球

          限制條件中彩球個數小于13
          因此用DP來計算復雜度為2^13*20*10是可以接受的
          這一題用memo方法更加合適因為會有大量的數據不需要計算
          每一次都迭代計算所有未填的球
          把球放進口袋或者直接開始填下一袋
          DP三個參數是mask,剩余袋數和本袋剩余空間
           1import java.util.*;
           2import java.util.regex.*;
           3import java.text.*;
           4import java.math.*;
           5import java.awt.geom.*;
           6
           7public class CollectingMarbles
           8{
           9    int[][][] dic;
          10    int L;
          11    int[] mw;
          12    int bagNumber;
          13    int cap;
          14    
          15    public int mostMarbles(int[] marblesWeights, int bagCapacity, int numberOfBags)
          16    {
          17        L = marblesWeights.length;
          18        mw = marblesWeights;
          19        bagNumber = numberOfBags;
          20        cap = bagCapacity;
          21        dic = new int[1<<L][bagNumber+1][cap+1];
          22        for(int[][] a : dic)
          23            for(int[] b : a)
          24                Arrays.fill(b, -1);
          25        int ans = recur(0, bagNumber, cap);
          26        return ans == -1? 0 : ans;
          27    }

          28    
          29    private int recur(int mask, int bagNumber, int cur) {
          30        // TODO Auto-generated method stub
          31        if(bagNumber == 0)
          32            return 0;
          33        if(dic[mask][bagNumber][cur] > -1)
          34            return dic[mask][bagNumber][cur];
          35        dic[mask][bagNumber][cur] = 0;
          36        for(int i = 0 ; i < L ; ++ i){
          37            if((mask & (1 << i)) == 0 && mw[i] <= cur){
          38                dic[mask][bagNumber][cur] = Math.max(dic[mask][bagNumber][cur],
          39                        1+recur(mask|1<<i, bagNumber, cur-mw[i]));
          40                
          41            }

          42            dic[mask][bagNumber][cur] = Math.max(dic[mask][bagNumber][cur], 
          43                    recur(mask, bagNumber-1, cap));
          44        }

          45        
          46        return dic[mask][bagNumber][cur];
          47    }

          48}
          posted @ 2009-12-15 15:15 jav7er 閱讀(144) | 評論 (0)編輯 收藏
           
          TopCoder SRM 398 Level2 900
          http://www.topcoder.com/stat?c=problem_statement&pm=8160
          一組字符串,如何將其中一部分右移若干格,使得某一列的縱向恰好為要求的字符串,并且給出移動最少的答案。

          這一題乍一看覺得很復雜
          有點像之前做過的吉他琴弦的那一題
          可是這個復雜度2^50是吃不消的
          但是這里有兩點不同
          一個是這里只能右移
          另一個很重要的是這個某一列將成為一個有參考意義的坐標
          即用這個列號來遍歷 看答案在哪一列解答最少
          想通這一點 后面就很容易了
           1import java.util.*;
           2import java.util.regex.*;
           3import java.text.*;
           4import java.math.*;
           5import java.awt.geom.*;
           6
           7public class MatchString
           8{
           9    public int placeWords(String matchString, String[] matchWords)
          10    {
          11        List<ArrayList<Integer> > occur = new ArrayList<ArrayList<Integer> >();
          12        int L = matchWords.length;
          13        int end = 0;
          14        int start = Integer.MAX_VALUE;
          15        int i,j;
          16        for(i = 0 ; i < L ; ++ i){
          17            ArrayList<Integer> temp = new ArrayList<Integer>();
          18            char c = matchString.charAt(i);
          19            for(j = 0 ; j < matchWords[i].length(); ++ j){
          20                if(matchWords[i].charAt(j) == c)
          21                    temp.add(j);
          22            }

          23            if(temp.isEmpty()) return -1;
          24            occur.add(temp);
          25            if(matchWords[i].length() > end)
          26                end = matchWords[i].length();
          27            if(temp.get(0< start)
          28                start = temp.get(0);
          29        }

          30        int ans = Integer.MAX_VALUE;
          31        Outer:
          32        for(i = start; i <= end; ++ i){
          33            int tempans = 0;
          34            for(int k = 0 ; k < L; ++ k){
          35                j = 0;
          36                while(j < occur.get(k).size() && occur.get(k).get(j) <= i)
          37                    ++j;
          38                if(j == 0)
          39                    continue Outer;
          40                tempans += i - occur.get(k).get(j-1);                
          41            }

          42            ans = Math.min(ans, tempans);
          43        }

          44        return ans;
          45    }

          46}
          posted @ 2009-12-15 15:09 jav7er 閱讀(192) | 評論 (0)編輯 收藏

          2009年11月19日

          TopCoder SRM 396 Level2 1000
          http://www.topcoder.com/stat?c=problem_statement&pm=8721&rd=12168
          給定一個字符串里面包含了若干個1~9的數字,另一個字符串為其子集,對于后者中每個字符,從前面字符串中刪去相應的一個數字
          求刪去剩下的數字的最大值

          由于是求最大值,直接在計算過程中不斷貪心在最高位謀取最大值
          從前面按照9~1的順序尋求可以做當前最高位的最大值
          分以下4步:
          1.對于所有都要刪去的數字,直接刪光
          2.從前面開始查找,將所有無法刪去的數字加入答案中
          3.從前面按照9~1的順序找可以用的最大值,如果其前面的所有數字都可以刪去,那么就取這個數,否則遞減
          4.若字符串為空則結束,否則循環第一步

          這一題足足做了2個多小時
          想法很快就有了
          但是在實現中String類型不能修改和刪除的問題很難處理
          最后干脆把String轉化為LinkedList來做
          不過沒有看答案解決掉很難得...繼續加油

           1import java.util.*;
           2import java.util.regex.*;
           3import java.text.*;
           4import java.math.*;
           5import java.awt.geom.*;
           6
           7public class RemovingDigits
           8{
           9    public String maxNumber(String number, String digits)
          10    {
          11        int[] numCnt = new int[10];
          12        int[] digCnt = new int[10];
          13        Arrays.fill(numCnt, 0);
          14        Arrays.fill(digCnt, 0);
          15        int i;
          16        for(i = 0 ; i < number.length(); ++ i)
          17            numCnt[number.charAt(i)-'0']++;
          18        for(i = 0 ; i < digits.length(); ++ i)
          19            digCnt[digits.charAt(i) - '0']++;
          20        StringBuilder ans = new StringBuilder("");
          21        List<Character> target = new LinkedList<Character>();
          22        for(i = 0 ; i < number.length(); ++ i){
          23            target.add(number.charAt(i));
          24        }

          25        while(!target.isEmpty()){
          26            //remove digits that all should be removed
          27            for(i = 1 ; i < 10 ; ++ i){
          28                if(numCnt[i] == digCnt[i]){
          29                    char c = (char) ('0'+i);
          30                    while(target.remove((Character)c));
          31//                    target.remove((Character)c);
          32                    numCnt[i] = 0;
          33                    digCnt[i] = 0;
          34                }

          35            }

          36            //append all that cannot be removed
          37            for(i = 0 ; i < target.size(); ++ i){
          38                if(digCnt[target.get(i)-'0'!= 0)
          39                    break;
          40                ans.append(target.get(i));                    
          41            }

          42            for(--i;i >= 0-- i){
          43                numCnt[target.get(i)-'0']--;
          44                target.remove(i);
          45            }

          46            if(target.isEmpty())
          47                break;
          48                    
          49            //find the largest head number
          50            Outer:
          51            for(i = 9 ; i > 0 ; -- i){
          52                //whether there is still this number
          53                if(numCnt[i] == 0)
          54                    continue;
          55                char c = (char) ('0'+i);
          56                int idx = target.indexOf((Character)c);
          57                int j;
          58                int[] tempCnt = new int[10];
          59                Arrays.fill(tempCnt, 0);
          60                for(j = 0 ; j < idx ; ++ j)
          61                    tempCnt[target.get(j)-'0']++;
          62                for(j = 1 ; j < 10++ j){
          63                    if(tempCnt[j] > digCnt[j])
          64                        continue Outer;
          65                }

          66                for(j = 1; j < 10++ j){
          67                    digCnt[j] -= tempCnt[j];
          68                    numCnt[j] -= tempCnt[j];
          69                }

          70                numCnt[i]--;
          71                ans.append(target.get(idx));
          72                for(j = idx; j >=0--j)
          73                    target.remove(j);
          74                break;
          75                
          76            }

          77        }

          78        return ans.toString();
          79    }

          80}
          posted @ 2009-11-19 20:21 jav7er 閱讀(131) | 評論 (0)編輯 收藏

          2009年11月18日

          TopCoder SRM 395 Level2 1000
          http://www.topcoder.com/stat?c=problem_statement&pm=8463&rd=11129
          標準的DP題目

          在運算中幾處忽略了比較檢查,特殊值
          導致錯誤了兩次
          做題目在主要思路有了之后還是要仔細考慮特殊情況
          往往人家關注的地方就在這里
           1import java.util.*;
           2import java.util.regex.*;
           3import java.text.*;
           4import java.math.*;
           5import java.awt.geom.*;
           6
           7public class TriviaGame
           8{
           9    public int maximumScore(int[] points, int tokensNeeded, int[] bonuses)
          10    {
          11        int L = points.length;
          12        int[][] dic = new int[L][tokensNeeded+1];
          13        for(int[] i:dic)
          14            Arrays.fill(i, -100000);
          15        int i;
          16        dic[0][0= -1 * points[0];
          17        dic[0][1= points[0];
          18        if(tokensNeeded == 1)
          19            dic[0][0= dic[0][1]+bonuses[0];
          20        for(i = 1; i < L; ++ i){
          21            if(dic[i-1][0- points[i] > dic[i][0])
          22                dic[i][0= dic[i-1][0- points[i];
          23            int j;
          24            for(j = 1; j < Math.min(i+2, tokensNeeded); ++ j){
          25                int a = dic[i-1][j-1+ points[i];
          26                int b = dic[i-1][j] - points[i];
          27                dic[i][j] = Math.max(a, b);                
          28            }

          29            if(j == tokensNeeded){
          30                dic[i][j] = dic[i-1][j-1+ points[i];
          31                dic[i][j] += bonuses[i];
          32                if(i != L - 1 && dic[i][j] > dic[i][0])
          33                    dic[i][0= dic[i][j];
          34            }

          35                
          36        }

          37        int max = dic[L-1][0];
          38        for(int in:dic[L-1])
          39            if(in > max)
          40                max = in;
          41        return max;
          42    }

          43}
          posted @ 2009-11-18 20:24 jav7er 閱讀(109) | 評論 (0)編輯 收藏
           

          TopCoder SRM 394 Level2 1000
          http://www.topcoder.com/stat?c=problem_statement&pm=8547&rd=11128
          求a到a+b所有的數的cool divider數量之和,即本身能被整除但是其n次方不能被整除

          由于數據高達10^7,暴力沒有可能,將乘法轉化為加法也仍然計算量太大
          答案給出了很好的解決方法
          對于a到a+b中間的數,可以整除i的個數為(a+b)/i - (a-1)/i,以上均為int的除法操作
          這樣大大節省了計算量
          唯一要注意的是如果b大于a,會將一部分值本身多計算一次
          因此最后要做一點修整

           

           1import java.util.*;
           2import java.util.regex.*;
           3import java.text.*;
           4import java.math.*;
           5import java.awt.geom.*;
           6
           7public class ProperDivisors
           8{
           9    public int analyzeInterval(int a, int b, int n)
          10    {
          11        int i,sum = 0;
          12        for(i = 2 ; i <= (a+b)/2++ i)
          13            sum += (a+b)/- (a-1)/i;
          14        for(i = 2 ; i <= (a+b)/2++ i){
          15            int k = pow(i,n);
          16            sum -= (a+b)/- (a-1)/k;
          17        }

          18        if(b >= a){
          19            sum -= (a+b)/2 - a + 1;
          20            if(a == 1) sum++;
          21        }

          22        
          23        return sum;
          24    }

          25    
          26    public int pow(int k, int n){
          27        int i;
          28        long result = k;
          29        for( i = 1 ; i < n; ++ i){
          30            result *= k;
          31            if(result > Integer.MAX_VALUE)
          32                return Integer.MAX_VALUE;
          33        }

          34        int res = (int)result;
          35        return res;
          36    }

          37}
          posted @ 2009-11-18 20:19 jav7er 閱讀(145) | 評論 (0)編輯 收藏

          2009年11月16日

          TopCoder SRM 390 Level2 1000
          http://www.topcoder.com/stat?c=problem_statement&pm=8307&rd=11124
          一組Pattern,每個位上是字母或者通配符“?”,求恰好符合K個Pattern的字符串數

          這個題目麻煩在恰好(exactly)上
          否則完全可以暴力處理
          這里要恰好,即符合K個而不符合K+1個
          用DP逐個位置處理
          計算出每個字母匹配的Pattern集合,再和前面的Pattern集合取交集計算這一行的結果
          計算過程中取交集的“&”錯寫成了“|” 太生疏了

           1import java.util.*;
           2import java.util.regex.*;
           3import java.text.*;
           4import java.math.*;
           5import java.awt.geom.*;
           6
           7public class SetOfPatterns
           8{
           9    public int howMany(String[] patterns, int k)
          10    {
          11        int[][] tab = new int[50][1<<15];
          12        int L = patterns.length;
          13        int T = 1 << L;
          14
          15        for(int[] i:tab)
          16            Arrays.fill(i, 0);
          17        int i,j;
          18        char c;
          19        for(i = 0 ; i < patterns[0].length(); ++ i){
          20            
          21            for(c = 'a'; c <= 'z'++ c){
          22                int mask = 0 ;
          23                for(j = 0 ; j < L ; ++ j){
          24                    if(patterns[j].charAt(i) == c || patterns[j].charAt(i) =='?')
          25                        mask |= 1 << j;
          26                }

          27                if(i == 0){
          28                    tab[i][mask]++;
          29                }

          30                else{
          31                    for(j = 0 ; j < (T); ++ j){
          32                        int fin = j & mask;
          33                        tab[i][fin] = (tab[i][fin] + tab[i-1][j])%1000003;
          34                    }

          35                }

          36            }

          37        }

          38        int ans=0;
          39        for(i = 0 ; i < T; ++ i){
          40            int cnt = 0;
          41            for(j = 0 ; j < L; ++ j){
          42                int temp = i & (1 << j);
          43                if(temp != 0)
          44                    cnt ++;
          45            }

          46            if(cnt == k)
          47                ans = (ans + tab[patterns[0].length()-1][i]) % 1000003;
          48        }

          49        return ans;
          50    }

          51}
          posted @ 2009-11-16 22:04 jav7er 閱讀(110) | 評論 (0)編輯 收藏

          2009年11月11日

               摘要: SRM 389 Level2 1000 http://www.topcoder.com/stat?c=problem_statement&pm=8545&rd=11123 吉他有若干根弦,和弦有若干個音,按某弦的某節可以改變其音 求某和弦的最簡單按發(各個弦按節最接近) 由于上限是6,數據比較小, 每個弦上需要考慮的點不超過12個 所以全部遍歷也只有12^6種情況 ...  閱讀全文
          posted @ 2009-11-11 20:18 jav7er 閱讀(118) | 評論 (0)編輯 收藏
          僅列出標題  下一頁
           
          主站蜘蛛池模板: 石屏县| 呼和浩特市| 清远市| 信丰县| 长顺县| 沛县| 江安县| 隆回县| 黄大仙区| 瑞金市| 水城县| 定边县| 禄劝| 长海县| 湖口县| 泗阳县| 汾阳市| 苗栗县| 香格里拉县| 长宁区| 敖汉旗| 北碚区| 马边| 华池县| 南靖县| 廊坊市| 台江县| 苏尼特右旗| 嘉义市| 济宁市| 博湖县| 红河县| 东城区| 浠水县| 海兴县| 孝义市| 永济市| 大悟县| 阳信县| 泸水县| 合江县|