結果
| 問題 |
No.5002 stick xor
|
| コンテスト | |
| ユーザー |
kurenai3110
|
| 提出日時 | 2018-05-26 02:18:27 |
| 言語 | C++11(廃止可能性あり) (gcc 13.3.0) |
| 結果 |
AC
|
| 実行時間 | 905 ms / 1,000 ms |
| コード長 | 6,723 bytes |
| コンパイル時間 | 31,598 ms |
| 実行使用メモリ | 1,704 KB |
| スコア | 43,881 |
| 最終ジャッジ日時 | 2018-05-26 02:19:01 |
|
ジャッジサーバーID (参考情報) |
judge10 / |
| 純コード判定しない問題か言語 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | AC * 32 |
ソースコード
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <chrono>
using namespace std;
class Timer {
chrono::high_resolution_clock::time_point start, end;
double limit;
public:
Timer() {
start = chrono::high_resolution_clock::now();
}
Timer(double l) {
start = chrono::high_resolution_clock::now();
limit = l;
}
double getTime() {
end = chrono::high_resolution_clock::now();
return chrono::duration<double>(end - start).count();
}
bool Over() {
if (getTime() > limit) {
return true;
}
return false;
}
void setLimit(double l) {
limit = l;
}
void setStart() { start = chrono::high_resolution_clock::now(); }
double getLimit() { return limit; }
};
class Xor128 {
unsigned static int x, y, z, w;
public:
Xor128() {
x = 31103110, y = 123456789, z = 521288629, w = 88675123;
}
unsigned int rand()
{
unsigned int t;
t = (x ^ (x << 11)); x = y; y = z; z = w;
return(w = (w ^ (w >> 19)) ^ (t ^ (t >> 8)));
}
};
unsigned int Xor128::x, Xor128::y, Xor128::z, Xor128::w;
const double TIMELIMIT = 0.9;
class Solver{
int N, K;
int L[500];
char A[60][60];
int sumA0[61][61], sumA1[61][61];
Timer tmr;
Xor128 xor128;
vector<pair<char, pair<int, int>>>ans, best_ans;
int best_score;
public:
void input() {
cin >> N >> K;
for (int i = 0; i < K; i++)cin >> L[i];
for (int i = 0; i < N; i++)for (int j = 0; j < N; j++) {
cin >> A[i][j];
A[i][j] -= '0';
}
}
void init() {
input();
tmr.setStart();
for (int i = 0; i <= N; i++) {
for (int j = 0; j <= N; j++) {
sumA0[i][j] = sumA1[i][j] = 0;
}
}
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
sumA0[i + 1][j] += sumA0[i][j] + A[i][j];
sumA1[i][j + 1] += sumA1[i][j] + A[i][j];
}
}
ans.resize(K, make_pair(-1, make_pair(0, 0)));
best_score = 0;
for (int i = 0; i < K; i++) {
best_score += scoring(0, 0, 0, i);
ans[i].first = 0;
update(0, 0, 0, i);
}
best_ans = ans;
tmr.setLimit(TIMELIMIT);
}
void SA() {
double startTemp = 1, endTemp = 0.05;
double diffTemp = (endTemp - startTemp) / TIMELIMIT;
double current_time = tmr.getTime();
int score = best_score;
int loop = 0;
int i = 0;
while (current_time < TIMELIMIT) {
loop++;
if (loop % 1000 == 0) {
current_time = tmr.getTime();
}
int change = -1e9;
bool mode;
int r, c;
for (int t = 0; t < L[i] + 2; t++) {
bool tmode = xor128.rand() % 2;
int tr = xor128.rand() % (N - L[i] + 1);
int tc = xor128.rand() % N;
if (tmode)swap(tr, tc);
if (t == 0) {
tmode = ans[i].first;
tr = ans[i].second.first;
tc = ans[i].second.second;
if (tmode) {
tc -= 1;
if (tc < 0)continue;
}
else {
tr -= 1;
if (tr < 0)continue;
}
}
else if (t == 1) {
tmode = ans[i].first;
tr = ans[i].second.first;
tc = ans[i].second.second;
if (tmode) {
tc += 1;
if (tc >= (N - L[i] + 1))continue;
}
else {
tr += 1;
if (tr >= (N - L[i] + 1))continue;
}
}
int tmp = scoring(tmode, tr, tc, i);
if (t < 2) if(current_time < TIMELIMIT*0.8)continue;
if (tmp >= change) {
mode = tmode;
r = tr;
c = tc;
change = tmp;
}
}
bool accept = false;
if (change >= 0)accept = true;
else if (change < -2)accept = false;
else {
double temp = startTemp + diffTemp * tmr.getTime();
double prob = exp(change / temp);
accept = prob * UINT32_MAX > xor128.rand();
}
if (accept) {
score += change;
update(ans[i].first, ans[i].second.first, ans[i].second.second, i);
ans[i].first = mode;
ans[i].second.first = r;
ans[i].second.second = c;
update(mode, r, c, i);
if (score > best_score) {
//cerr << current_time << " " << best_score << endl;
best_score = score;
best_ans = ans;
}
}
i = (i + 1) % K;
}
cerr << tmr.getTime() << endl;
cerr << loop << endl;
cerr << best_score << endl;
}
int scoring(int mode, int r, int c, int i) {
int change = 0;
if (ans[i].first != -1) {
int r = ans[i].second.first;
int c = ans[i].second.second;
int mode = ans[i].first;
if (mode) change += (sumA1[r][c + L[i]] - sumA1[r][c]);
else change += (sumA0[r + L[i]][c] - sumA0[r][c]);
}
if (mode) change += (sumA1[r][c + L[i]] - sumA1[r][c]);
else change += (sumA0[r + L[i]][c] - sumA0[r][c]);
change -= L[i];
int r1, r2;
r1 = r; r2 = ans[i].second.first;
int c1, c2;
c1 = c; c2 = ans[i].second.second;
if (mode == ans[i].first) {
if (mode == true && r1 == r2) {
if (c1 > c2)swap(c1, c2);
if (c1 + L[i] > c2)change += ((c1 + L[i] - c2) - 2 * (sumA1[r][c1 + L[i]] - sumA1[r][c2]));
}
if (mode == false && c1 == c2) {
if (r1 > r2)swap(r1, r2);
if (r1 + L[i] > r2)change += ((r1 + L[i] - r2) - 2 * (sumA0[r1 + L[i]][c] - sumA0[r2][c]));
}
}
else if (ans[i].first != -1) {
if (mode) {
if (c1 <= c2 && c2 <= c1 + L[i] - 1 && r2 <= r1 && r1 <= r2 + L[i] - 1) {
change -= (A[r1][c2] ? 1 : -1);
}
}
else {
if (r1 <= r2 && r2 <= r1 + L[i] - 1 && c2 <= c1 && c1 <= c2 + L[i] - 1) {
change -= (A[r2][c1] ? 1 : -1);
}
}
}
change *= 2;
if (ans[i].first == -1)change += L[i];
return change;
}
void update(int mode, int r, int c, int i) {
int rev_mode = mode ^ 1;
if (mode) {
int p = 0;
for (int j = c; j < c + L[i]; j++) {
if(mode)sumA1[r][j] += p;
else sumA0[r][j] += p;
int p2 = (A[r][j] ? -1 : 1);
for (int k = r + 1; k <= N; k++) {
if(rev_mode)sumA1[k][j] += p2;
else sumA0[k][j] += p2;
}
p += (A[r][j] ? -1 : 1);
A[r][j] ^= 1;
}
for (int j = c + L[i]; j <= N; j++) {
if (mode)sumA1[r][j] += p;
else sumA0[r][j] += p;
}
}
else {
int p = 0;
for (int j = r; j < r + L[i]; j++) {
if (mode)sumA1[j][c] += p;
else sumA0[j][c] += p;
int p2 = (A[j][c] ? -1 : 1);
for (int k = c + 1; k <= N; k++) {
if(rev_mode)sumA1[j][k] += p2;
else sumA0[j][k] += p2;
}
p += (A[j][c] ? -1 : 1);
A[j][c] ^= 1;
}
for (int j = r + L[i]; j <= N; j++) {
if (mode)sumA1[j][c] += p;
else sumA0[j][c] += p;
}
}
}
void output() {
for (int i = 0; i < K; i++) {
cout << best_ans[i].second.first + 1 << " " << best_ans[i].second.second + 1 << " ";
if (best_ans[i].first)cout << best_ans[i].second.first + 1 << " " << best_ans[i].second.second + L[i] << endl;
else cout << best_ans[i].second.first + L[i] << " " << best_ans[i].second.second + 1 << endl;
}
}
void run() {
init();
SA();
output();
}
};
int main() {
Solver slv;
slv.run();
return 0;
}
kurenai3110