ACM - Псков

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » ACM - Псков » TopCoder » SRM 432 DIV 1


SRM 432 DIV 1

Сообщений 1 страница 2 из 2

1

Задача на 250 баллов
Условие: http://www.topcoder.com/stat?c=problem_ … p;rd=13694

Дана матрица единиц и нулей (vector <string>) Размер 50х50.
И К (до 1000) - количество переключений. Переключение заключается в инвертировании всех элементов любого столбца. Нужно определить,
какое максимальное количество строк, состоящих только из единиц после ровно К переключений.

Пример:
01
10
10
К = 173
Ответ: 2

Решение
Строка может попасть в ответ, если количество нулей в ней <= К и имеет одинаковую с К чётность.
Для каждой подходящей под это условие строки нужно посчитать, сколько раз она встречается в векторе и вернуть максимальное количество.

Моя реализация:

Код:
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>

using namespace std;

#define VS vector <string>

map <string, int> nm;
map <string, int> ke;

void fnd(VS &vs){
     int key=0;
     int num=1;
     for(int i=0;i<vs.size();++i){
          for(int j=0;j<vs[i].size();++j){
               if(vs[i][j]=='0')key++;
          }
          for(int j=i+1;j<vs.size();++j){
               if(vs[i]==vs[j]){
                    num++;
               }
          }
          if(nm[vs[i]]<num){
               nm[vs[i]]=num;
               ke[vs[i]]=key;
          }
          key=0;
          num=1;
     }
}

class LampsGrid {
public:
     int mostLit(vector <string>, int);
};

int LampsGrid::mostLit(vector <string> initial, int K) {
     fnd(initial);
     int ans=0;
     for(int i=0;i<initial.size();++i){
          if(ke[initial[i]]<=K && (K%2 == ke[initial[i]]%2) ){
               if(nm[initial[i]]>ans){
                    ans=nm[initial[i]];
               }
          }
     }
     return ans;
}

Задача на 500 баллов
Условие: http://www.topcoder.com/stat?c=problem_ … p;rd=13694

Строка называется "сгруппированная", если между любыми двумя одинаковыми буквами нед буквы другого типа.
Например "aaabbbccc", "hhhffffrtty" , "ab" - "сгруппированные"
"aba", "cbadb" -"несгруппированная"
Дан набор строк. Требуется определить, мог ли он быть получен путём разрезания  "сгруппированной" строки на части.
Если мог быть получен из единственной строки - вернуть её.
Если из нескольких - вернуть MANY
Если не мог - IMPOSSIBLE

Решение - жадина  :angry:

1) Переместить все простые строки (из одинаковых символов) в начало вектора
2) Циклично проводить объединения строк, пока они возможны. (объединение двух строк возможно, если первый символ одной совпадает с
последним символом второй)
3) Если получилась одна строка, и она "сгруппированная" то вернуть её
4) Если осталось несколько строк и все они "сгруппированные" то вернуть MANY
5) Иначе вернуть IMPOSSIBLE

Эту задачу я решал во время контеста, как показало вскрытие, подвела реализация. Переписал почерпнув идеи с форума топкодера.

Реализация:

Код:
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>

using namespace std;

#define VS vector<string> 

void srt(VS &vs){
     VS tmp;
     for(int i=0;i<vs.size();++i){
          if(vs[i][0]==vs[i][vs[i].size()-1]){
               tmp.push_back(vs[i]);
          }
     }
     for(int i=0;i<vs.size();++i){
          if(vs[i][0]!=vs[i][vs[i].size()-1]){
               tmp.push_back(vs[i]);
          }
     }     
     vs=tmp;
}

bool good(string &st){
     for(int i=0;i<st.size();++i){
          for(int j=i+1;j<st.size();++j){
               if(st[i]==st[j]){
                    for(int k=i+1;k<j;++k){
                         if(st[k]!=st[i])return false;
                    }
               }
          }
     }
     return true;
}

bool join1 (VS &vs){
     for(int i=0;i<vs.size();++i){
          for(int j=i+1;j<vs.size();++j){
               if(vs[i][vs[i].size()-1]==vs[j][0]){
                    vs[i]+=vs[j];
                    vs.erase(vs.begin()+j);
                    return true;
               }
          }
     }
     return false;
}

bool join2 (VS &vs){
     for(int i=0;i<vs.size();++i){
          for(int j=i+1;j<vs.size();++j){
               if(vs[j][vs[j].size()-1]==vs[i][0]){
                    vs[i]=vs[j]+vs[i];
                    vs.erase(vs.begin()+j);
                    return true;
               }
          }
     }
     return false;
}

bool prov (string &s1, string &s2){
     for(int i=0;i<s1.size();++i){
          for(int j=0;j<s2.size();++j){
               if(s1[i] == s2[j])return false;
          }
     }
     return true;
}

class GroupedWord {
public:
     string restore(vector <string>);
};

string GroupedWord::restore(vector <string> parts) {
     for(int i=0;i<parts.size();++i){
          if(!good(parts[i]))return "IMPOSSIBLE";
     }
     srt(parts);
     while(join1(parts));
     while(join2(parts));
     for(int i=0;i<parts.size();++i){
          if(!good(parts[i]))return "IMPOSSIBLE";
     }
     if(parts.size()>1){
          for(int i=0;i<parts.size();++i){
               for(int j=i+1;j<parts.size();++j){
                    if(!prov(parts[i], parts[j])){
                         return "IMPOSSIBLE";
                    }
               }
          }
          return "MANY";
     }
     if(!good(parts[0]))return "IMPOSSIBLE";
     return parts[0];
}

2

Да, у 500 идея решения очень простая. А я на контесте как всегда перемудрил, построил какой-то граф между словами, циклы искал... чушь короче((


Вы здесь » ACM - Псков » TopCoder » SRM 432 DIV 1