虽然是半退役选手了..但感觉这个比赛挺有趣的ww 打算补补题
UOJ526: 运气游戏 large
牌的总集合数只有 $ 5^9 < 2000000 $
可以DP求出每种集合能否胡牌
对于天选情况,枚举最后一张牌
此时前两个AI能否获胜 只与之前牌的集合有关
第三个AI取决于最后 13 张牌
我们枚举集合,并且容易发现:确定后 13 张牌每种有几张之后 容易列出式子
可以用子集卷积计算
总运算量 $ 9^2 * 5^9 $ ;本机大概2s可以出解
代码如下:
//Awwawa! Dis cold yis ratten buy tEMMIE!
#include <bits/stdc++.h>
#define ll long long
#define mod 998244353
#define db double
#define vi vector<int>
#define pb push_back
#define mp make_pair
#define pi pair<int, int>
#define fi first
#define se second
template <typename T> bool chkmax(T &x,T y){return x<y?x=y,true:false;}
template <typename T> bool chkmin(T &x,T y){return x>y?x=y,true:false;}
using namespace std;
ll ksm(ll a, ll b) {
if (!b) return 1;
ll ns = ksm(a, b >> 1);
ns = ns * ns % mod;
if (b & 1) ns = ns * a % mod;
return ns;
}
int tw[10];
// 0 ~ 8
const int N = 2000005;
bool fl[N];
int cnt[N];
ll S[N];
ll ans[100];
ll jc[105], bjc[105];
int main() {
jc[0] = bjc[0] = 1;
for (int i = 1; i < 105; i++)
jc[i] = jc[i - 1] * i % mod,
bjc[i] = ksm(jc[i], mod - 2); //阶乘,阶乘逆元
tw[0] = 1;
for (int j = 1; j < 10; j++)
tw[j] = tw[j - 1] * 5;
for (int j = 0; j < tw[9]; j++) {
//判断能不能胡
int r[9];
for (int k = 0; k < 9; k++)
r[k] = (j / tw[k]) % 5;
cnt[j] = 0;
for (int s = 0; s < 9; s++)
cnt[j] += r[s];
if (cnt[j] > 14) fl[j] = 0;
else if (cnt[j] % 3 != 2) fl[j] = 0;
else {
if (cnt[j] == 2) {
for (int l = 0; l < 9; l++)
if (r[l] == 2) fl[j] = 1;
}
else {
for (int l = 0; l < 9; l++)
if (r[l] >= 3) fl[j] |= fl[j - tw[l] * 3];
for (int l = 0; l < 7; l++)
if (r[l] && r[l + 1] && r[l + 2])
fl[j] |= fl[j - tw[l] * 31];
}
}
if (cnt[j] == 14) { // 七小对
int ff = 1;
for (int l = 0; l < 9; l++)
if (r[l] != 2 && r[l] != 0) ff = 0;
if (ff) fl[j] = 1;
}
}
for (int k = 0; k < 9; k++) {
for (int j = 0; j < tw[9]; j++) {
if (cnt[j] == 13 && (j / tw[k] % 5 != 4) && fl[j + tw[k]]) { // 处理能不能赢
int r[9];
for (int k = 0; k < 9; k++)
r[k] = (j / tw[k]) % 5;
S[j] = 1;
for (int l = 0; l < 9; l++)
S[j] = 1ll * S[j] * bjc[r[l]] % mod;
}
else S[j] = 0;
}
//子集求和
// 方法数 : 13! * (cnt[j] - 13)! * (36 -cnt[j])! / 后 13 张中个数! / 前 cnt[j] - 13 张中个数!
for (int q = 0; q < 9; q++)
for (int j = tw[9] - 1; j >= 0; j--) { // 子集卷积
if (cnt[j] < 13) continue;
int l = j / tw[q] % 5;
for (int s = 1; s <= l; s++)
S[j] = (S[j] + 1ll * S[j - s * tw[q]] * bjc[s]) % mod;
}
for (int j = 0; j < tw[9]; j++) {
if ((j / tw[k] % 5 == 4)) continue;
if (!S[j]) continue;
if (cnt[j] < 13) continue;
int r[9];
for (int k = 0; k < 9; k++)
r[k] = (j / tw[k]) % 5;
int fr = 0, cn = 13;
for (int k = 0; k < 9; k++) {
int cu = min(cn, r[k]);
fr += cu * tw[k], cn -= cu;
}
if (!fl[fr + tw[k]]) continue;
fr = 0, cn = 13;
for (int k = 8; k >= 0; k--) {
int cu = min(cn, r[k]);
fr += cu * tw[k], cn -= cu;
}
if (!fl[fr + tw[k]]) continue;
ll w = S[j] * jc[13] % mod * jc[cnt[j] - 13] % mod;
w = w * jc[36 - cnt[j] - 1] % mod;
r[k]++;
for (int j = 0; j < 9; j++)
w = w * bjc[4 - r[j]] % mod;
ans[cnt[j] - 12] = (ans[cnt[j] - 12] + w) % mod;
}
}
for (int j = 1; j <= 23; j++)
cout << ans[j] << endl;
cout << 1.0 * clock() / CLOCKS_PER_SEC << endl;
return 0;
}
UOJ#521: 魔塔
交互可以从GCJ交互库抄
# This code can be run as python2 or python3 in most systems.
#
# This is a small program that runs two processes, connecting the stdin of each
# one to the stdout of the other.
# It doesn't perform a lot of checking, so many errors may
# be caught internally by Python (e.g., if your command line has incorrect
# syntax) or not caught at all (e.g., if the judge or solution hangs).
#
# Run this as:
# python interactive_runner.py <cmd_line_judge> -- <cmd_line_solution>
#
# For example, if you have a testing_tool.py in python3 (that takes a single
# integer as a command line parameter) to use as judge -- like one
# downloaded from a problem statement -- and you would run your solution
# in a standalone using one of the following:
# 1. python3 my_solution.py
# 2. ./my_solution
# 3. java Solution
# 4. my_solution.exe
# Then you could run the judge and solution together, using this, as:
# 1. python interactive_runner.py python3 testing_tool.py 0 -- python3 my_solution.py
# 2. python interactive_runner.py python3 testing_tool.py 0 -- ./my_solution
# 3. python interactive_runner.py python3 testing_tool.py 0 -- java solution
# 4. python interactive_runner.py python3 testing_tool.py 0 -- my_solution.exe
# Notice that the solution in cases 2, 3 and 4 would usually have a
# compilation step before running, which you should run in your usual way
# before using this tool.
#
# This is only intended as a convenient tool to help contestants test solutions
# locally. In particular, it is not identical to the implementation on our
# server, which is more complex.
#
# The standard streams are handled the following way:
# - judge's stdin is connected to the solution's stdout;
# - judge's stdout is connected to the solution's stdin;
# - stderrs of both judge and solution are piped to standard error stream, with
# lines prepended by "judge: " or "sol: " respectively (note, no
# synchronization is done so it's possible for the messages from both programs
# to overlap with each other).
from __future__ import print_function
import sys, subprocess, threading
class SubprocessThread(threading.Thread):
def __init__(self,
args,
stdin_pipe=subprocess.PIPE,
stdout_pipe=subprocess.PIPE,
stderr_prefix=None):
threading.Thread.__init__(self)
self.stderr_prefix = stderr_prefix
self.p = subprocess.Popen(
args, stdin=stdin_pipe, stdout=stdout_pipe, stderr=subprocess.PIPE)
def run(self):
try:
self.pipeToStdErr(self.p.stderr)
self.return_code = self.p.wait()
self.error_message = None
except (SystemError, OSError):
self.return_code = -1
self.error_message = "The process crashed or produced too much output."
# Reads bytes from the stream and writes them to sys.stderr prepending lines
# with self.stderr_prefix.
# We are not reading by lines to guard against the case when EOL is never
# found in the stream.
def pipeToStdErr(self, stream):
new_line = True
while True:
chunk = stream.readline(1024)
if not chunk:
return
chunk = chunk.decode("UTF-8")
if new_line and self.stderr_prefix:
chunk = self.stderr_prefix + chunk
new_line = False
sys.stderr.write(chunk)
if chunk.endswith("\n"):
new_line = True
sys.stderr.flush()
assert sys.argv.count("--") == 1, (
"There should be exactly one instance of '--' in the command line.")
sep_index = sys.argv.index("--")
judge_args = sys.argv[1:sep_index]
sol_args = sys.argv[sep_index + 1:]
t_sol = SubprocessThread(sol_args, stderr_prefix=" sol: ")
t_judge = SubprocessThread(
judge_args,
stdin_pipe=t_sol.p.stdout,
stdout_pipe=t_sol.p.stdin,
stderr_prefix="judge: ")
t_sol.start()
t_judge.start()
t_sol.join()
t_judge.join()
# Print an empty line to handle the case when stderr doesn't print EOL.
print()
print("Judge return code:", t_judge.return_code)
if t_judge.error_message:
print("Judge error message:", t_judge.error_message)
print("Solution return code:", t_sol.return_code)
if t_sol.error_message:
print("Solution error message:", t_sol.error_message)
if t_sol.return_code:
print("A solution finishing with exit code other than 0 (without exceeding "
"time or memory limits) would be interpreted as a Runtime Error "
"in the system.")
elif t_judge.return_code:
print("A solution finishing with exit code 0 (without exceeding time or "
"memory limits) and a judge finishing with exit code other than 0 "
"would be interpreted as a Wrong Answer in the system.")
else:
print("A solution and judge both finishing with exit code 0 (without "
"exceeding time or memory limits) would be interpreted as Correct "
"in the system.")
用法是 python inter.py A.exe -- B.exe (假如这份 python 代码被保存为inter.py)
然后就可以让A,B互相喂东西啦
至于魔塔玩法,随便写个贪心调调参就行~
代码如下
//Awwawa! Dis cold yis ratten buy tEMMIE!
#include <bits/stdc++.h>
#define ll long long
#define maxn 100005 /*rem*/
#define mod 998244353
#define db double
#define vi vector<int>
#define pb push_back
#define mkp make_pair
#define pi pair<int, int>
#define fi first
#define se second
template <typename T> bool chkmax(T &x,T y){return x<y?x=y,true:false;}
template <typename T> bool chkmin(T &x,T y){return x>y?x=y,true:false;}
using namespace std;
ll ksm(ll a, ll b) {
if (!b) return 1;
ll ns = ksm(a, b >> 1);
ns = ns * ns % mod;
if (b & 1) ns = ns * a % mod;
return ns;
}
int mv[4][2] = {{-1, 0}, {0, -1}, {1, 0}, {0, 1}};
char r[4] = {'W', 'A', 'S', 'D'};
char mp[20][20];
int cnt[3] = {0, 0, 0};
int s[3] = {'r', 'b', 'g'};
int b[3] = {'R', 'B', 'G'};
char inp[100];
void rd() {
cin.getline(inp, 100);
}
void readmap() {
int cnt = 0;
while (1) {
rd();
if (inp[0] != '#') continue;
int l = strlen(inp);
for (int j = 0; j < l; j++)
mp[cnt][j] = inp[j];
cnt++;
if (cnt > 1 && inp[5] == '#') break;
}
// cerr << "READMAP" << endl;
}
void readkey() {
rd();
int l = strlen(inp);
int q = 0;
for (int j = 0; j < l; j++)
if (inp[j] >= '0' && inp[j] <= '9')
cnt[q++] = inp[j] - '0';
}
db f[10] = {0, 1.3, 2, 2.4, 2.6, 2.7, 2.7, 2.7, 2.7};
int gm[30][30][3];
vi tr[20][20];
int tot = 0;
int nm = 1;
void work() {
tot++;
queue<pi> x;
memset(gm, -1, sizeof(gm));
for (int i = 0; i < 20; i++)
for (int j = 0; j < 20; j++) {
tr[i][j].clear();
if (mp[i][j] == 'P') {
x.push(mkp(i, j));
for (int u = 0; u < 3; u++)
gm[i][j][u] = cnt[u];
}
}
while (!x.empty()) {
pi q = x.front();
x.pop();
for (int tp = 0; tp < 4; tp++) {
int ex = q.fi + mv[tp][0], ey = q.se + mv[tp][1];
if (gm[ex][ey][0] != -1) continue;
if (mp[ex][ey] == '#') continue;
int e[3];
for (int j = 0; j < 3; j++)
e[j] = gm[q.fi][q.se][j];
int fl = 1;
for (int j = 0; j < 3; j++)
if (mp[ex][ey] == b[j]) {
e[j]--;
if (e[j] < 0) fl = 0;
}
else if (mp[ex][ey] == s[j])
e[j]++;
if (!fl) continue;
tr[ex][ey] = tr[q.fi][q.se];
tr[ex][ey].pb(tp);
for (int s = 0; s < 3; s++)
gm[ex][ey][s] = e[s];
x.push(mkp(ex, ey));
}
}
db ans = -1000;
pi fn;
for (int i = 0; i < 20; i++)
for (int j = 0; j < 20; j++) {
if (gm[i][j][0] == -1) continue;
if (mp[i][j] == ' ') continue;
if (mp[i][j] == '#') continue;
if (mp[i][j] == 'P') continue;
db ed = 0;
if (mp[i][j] == '?') {
// cout << "!!" << i << ' ' << j << ed << endl;
ed = 0;
for (int r = 0; r < 3; r++) {
gm[i][j][r]++;
for (int u = 0; u < 3; u++)
ed += f[gm[i][j][r]];
gm[i][j][r]--;
}
ed /= 3;
}
if (mp[i][j] == '@')
ed = 10000000;
for (int t = 0; t < 3; t++)
if (mp[i][j] == s[t]) {
for (int u = 0; u < 3; u++)
ed += f[gm[i][j][u]];
}
ed *= 10000;
ed -= tr[i][j].size();
if (ed > ans) {
ans = ed;
fn = mkp(i, j);
}
}
if (ans < 0)
cout << "R" << endl,
cerr << "RESTART " << tot << endl;
else {
cout << r[tr[fn.fi][fn.se][0]] << endl;
if (tr[fn.fi][fn.se].size() == 1 && mp[fn.fi][fn.se] == '@') {
nm++;
cerr << nm << ' ' << tot << endl;
if (nm >= 110) exit(0);
}
}
}
int main() {
cout << 69635 << endl;
while (1) {
readmap();
readkey();
work();
}
return 0;
}
前些日子在过520学数学,咕了几天
今天继续更新啦
写了一下魔塔随机情况的最优解
大致思路是,待定一个权值作为每层的期望步数;认为Restart的代价是权值 + 1
记搜求每种局面的期望步数(需要对状态剪剪枝ww)
二分这个权值,使得初始局面的DP值和权值尽量接近
最后每层的期望是223..总步数22300左右
现在排在rk2 可能因为没有save load? (它的随机数是固定的qwq)
代码如下
//Awwawa! Dis cold yis ratten buy tEMMIE!
#include <bits/stdc++.h>
#define ll long long
#define maxn 100005 /*rem*/
#define mod 998244353
#define db double
#define vi vector<int>
#define pb push_back
#define mkp make_pair
#define pi pair<int, int>
#define fi first
#define se second
template <typename T> bool chkmax(T &x,T y){return x<y?x=y,true:false;}
template <typename T> bool chkmin(T &x,T y){return x>y?x=y,true:false;}
using namespace std;
ll ksm(ll a, ll b) {
if (!b) return 1;
ll ns = ksm(a, b >> 1);
ns = ns * ns % mod;
if (b & 1) ns = ns * a % mod;
return ns;
}
int mv[4][2] = {{-1, 0}, {0, -1}, {1, 0}, {0, 1}};
char r[4] = {'W', 'A', 'S', 'D'};
char mp[20][20];
int cnt[3] = {0, 0, 0};
int s[3] = {'r', 'b', 'g'};
int b[3] = {'R', 'B', 'G'};
char inp[100];
struct state {
char mp[20][20];
int pl[2];
bool operator < (const state &x)const {
for (int i = 0; i < 20; i++)
for (int j = 0; j < 20; j++)
if (mp[i][j] != x.mp[i][j]) return mp[i][j] < x.mp[i][j];
return 0;
}
};
map<state, int> id;
const int N = 100005;
const int mx = 7;
bool hv[N];
db cal[N][mx][mx][mx];
vi nx[N][mx][mx][mx];
int tt[N];
void rd() {
cin.getline(inp, 100);
}
int tms = 0;
void readmap() {
int cnt = 0;
while (1) {
rd();
if (inp[0] != '#') continue;
int l = strlen(inp);
for (int j = 0; j < l; j++)
mp[cnt][j] = inp[j];
cnt++;
if (cnt > 1 && inp[5] == '#') break;
}
// cerr << "READMAP" << endl;
}
void readkey() {
rd();
int l = strlen(inp);
int q = 0;
for (int j = 0; j < l; j++)
if (inp[j] >= '0' && inp[j] <= '9')
cnt[q++] = inp[j] - '0';
}
state cur;
void rdstate() {
tms++;
readmap();
readkey();
for (int i = 0; i < 20; i++)
for (int j = 0; j < 20; j++) {
cur.mp[i][j] = mp[i][j];
if (mp[i][j] == 'P')
cur.pl[0] = i, cur.pl[1] = j;
}
}
int fl = 0;
db weight;
int idcnt = 0;
bool chkv(char x) {
return x == 'r' || x == 'b' || x == 'g' || x == '?' || x == '@';
}
bool chkd(char x) {
return x == 'R' || x == 'B' || x == 'G';
}
const int cut_1 = 1;
void uniform(state &r) {
if (r.mp[11][4] == ' ') {
r.mp[11][4] = 'B', r.mp[9][4] = ' ';
}
if (r.mp[10][4] == ' ') {
r.mp[10][4] = 'G', r.mp[9][4] = ' ';
}
}
void otp(state r) {
for (int i = 0; i < 20; i++) {
for (int j = 0; j < 20; j++)
cout << r.mp[i][j];
cout << endl;
}
}
void dp(state r) {
uniform(r);
if (!id[r]) id[r] = ++idcnt;
int cid = id[r];
if (hv[cid]) return;
assert(idcnt < N);
int gm[20][20][3];
pi fr[20][20];
hv[cid] = 1;
int tot = 0;
for (int m = 0; m < 20; m++)
for (int l = 0; l < 20; l++)
if (mp[m][l] != r.mp[m][l]) {
if (chkv(mp[m][l])) tot++;
if (chkd(mp[m][l])) tot--;
}
tt[cid] = tot;
int ms = -1;
for (int tp = 0; tp < 4; tp++) {
int ex = r.pl[0] + mv[tp][0], ey = r.pl[1] + mv[tp][1];
char qr = r.mp[ex][ey];
if (chkv(qr)) ms = tp;
}
for (int i = 0; i < mx; i++)
for (int j = 0; j < mx; j++)
for (int k = 0; k < mx; k++)
cal[cid][i][j][k] = 1 + weight,
nx[cid][i][j][k].clear();
queue<pi> x;
int u = r.pl[0], v = r.pl[1];
x.push(mkp(u, v));
int inf = 105;
for (int i = 0; i < 20; i++)
for (int j = 0; j < 20; j++)
gm[i][j][0] = gm[i][j][1] = gm[i][j][2] = -inf;
for (int j = 0; j < 3; j++)
gm[u][v][j] = 0;
while (!x.empty()) {
pi q = x.front();
x.pop();
for (int tp = 0; tp < 4; tp++) {
int ex = q.fi + mv[tp][0], ey = q.se + mv[tp][1];
if (gm[ex][ey][0] != -inf)
continue;
if (r.mp[ex][ey] == '#') continue;
int e[3];
for (int j = 0; j < 3; j++)
e[j] = gm[q.fi][q.se][j];
for (int j = 0; j < 3; j++)
if (r.mp[ex][ey] == b[j])
e[j]--;
else if (r.mp[ex][ey] == s[j])
e[j]++;
for (int s = 0; s < 3; s++)
gm[ex][ey][s] = e[s];
fr[ex][ey] = q;
if (chkv(r.mp[ex][ey])) continue;
x.push(mkp(ex, ey));
}
}
for (int i = 0; i < 20; i++)
for (int j = 0; j < 20; j++) {
if (!chkv(r.mp[i][j])) continue;
if (ms != -1 && mkp(i, j) != mkp(u + mv[ms][0], v + mv[ms][1])) continue;
if (gm[i][j][0] == -inf) continue;
state uf = r;
pi cm = mkp(i, j);
int tp = 0;
if (r.mp[i][j] == '?') tp = 1;
int nd = -(gm[i][j][0] + gm[i][j][1] + gm[i][j][2]) + 1 - tp;
if (r.mp[i][j] == '@') nd--;
if (nd > tot) continue;
vi qq;
while (1) {
uf.mp[cm.fi][cm.se] = ' ';
if (cm == mkp(u, v)) break;
pi fs = cm;
cm = fr[cm.fi][cm.se];
for (int m = 0; m < 4; m++)
if (fs.fi - cm.fi == mv[m][0] && fs.se - cm.se == mv[m][1])
qq.pb(m);
}
reverse(qq.begin(), qq.end());
uf.pl[0] = i, uf.pl[1] = j;
uf.mp[i][j] = 'P';
int eid;
if (r.mp[i][j] == '@')
eid = idcnt + 10;
else uniform(uf), dp(uf), eid = id[uf];
int u[3];
int ff = 0;
if (cid == 2) {
assert(eid == 3);
db em = cal[3][0][0][1] + cal[3][0][1][0] + cal[3][1][0][0];
em /= 3;
vi f = {0, 3, 3, 3, 2, 2};
if (chkmin(cal[cid][1][0][0], em + f.size())) nx[cid][1][0][0] = f;
f = {3, 2, 3, 3};
if (chkmin(cal[cid][0][1][0], em + f.size())) nx[cid][0][1][0] = f;
f = {3, 3, 3, 2};
if (chkmin(cal[cid][0][0][1], em + f.size())) nx[cid][0][0][1] = f;
}
else {
for (u[0] = 0; u[0] < mx; u[0]++)
for (u[1] = 0; u[1] < mx; u[1]++)
for (u[2] = 0; u[2] < mx && u[2] + u[1] + u[0] <= tot; u[2]++) {
int m[3] = {u[0] + gm[i][j][0], u[1] + gm[i][j][1], u[2] + gm[i][j][2]};
if (m[0] < 0 || m[1] < 0 || m[2] < 0) continue;
char ed = r.mp[i][j];
if (ed == s[0] && m[0] == 0) continue;
if (ed == s[1] && m[1] == 0) continue;
if (ed == s[2] && m[2] == 0) continue;
if (m[0] >= mx || m[1] >= mx || m[2] >= mx) continue;
db nans = 0;
if (!tp) nans += cal[eid][m[0]][m[1]][m[2]];
else {
for (int j = 0; j < 3; j++) {
m[j]++;
if (m[0] >= mx || m[1] >= mx || m[2] >= mx) nans += 1 + weight;
else
nans += cal[eid][m[0]][m[1]][m[2]];
m[j]--;
}
nans /= 3;
}
nans += qq.size();
if (chkmin(cal[cid][u[0]][u[1]][u[2]], nans))
nx[cid][u[0]][u[1]][u[2]] = qq;
}
}
}
}
void init() {
if (fl) return ;
fl = 1;
weight = 223;
dp(cur);
cerr << cal[1][0][0][0] << endl;
}
int main() {
cout << 2405576 << endl;
int cn = 0;
while (1) {
rdstate();
init();
uniform(cur);
// otp(cur);
if (id[cur] == 1) {
cn++;
cerr << "FLOOR" << cn << ' ' << tms << endl;
}
vi tp = nx[id[cur]][cnt[0]][cnt[1]][cnt[2]];
if (!tp.size()) {
cout << "R" << endl;
cerr << "RESTART" << ' ' << tms << endl;
cn--;
}
else {
for (int j = 0; j < tp.size(); j++) {
cout << r[tp[j]] << endl;
if (j != tp.size() - 1) rdstate();
}
}
}
return 0;
}
/*
Level: 1
Answer to the small task: Unlock after reaching level 2.
Answer to the large task: Unlock after reaching level 100.
#################
##### Bb?Gr######
##### ###########
#?RbR GgR?B??####
##### ###########
#?GrG BGR?????###
##### ###########
#?BgB G?G???Rb###
##### ###########
# R RrG?B???Bg#
# ? G ###########
#P B?RRRGGGBBB@#
#################
You keep 0 red keys, 0 blue keys, 0 green keys
Please enter your choice (move: WASD, restart: R):
*/