这周打了两场比赛,一场是TC 701,一场是BC Round #89,最终结果都非常不理想,所以在这里总(fa)结(lao sao)一下。
TC 701
比赛前还是很有信心的,毕竟不做挂基本能涨涨rating就到红名了。一开始看题,第一题第一眼看上去是找个循环节直接做,但是思路不清晰,而且整个人都很紧张,然后就一直在想有没有什么其他规律能不能用其他做法之类的,一直看了20多分钟第一题,然后觉得再做第一题就没希望了,点开第二题,觉得不会做,好复杂,然后又点开第三题,两题都没思路,结果两边一起想,最后一题都没有做出来。rating从2050掉会18**,直接把上场涨的全掉了回来。
BC #89
一开始点开第一题,发现不会啊,好难,然后发现可以枚举公比,交上去过了pretest,然后开第二题,发现是傻逼题,码的很急,一开始过不了样例,直接打了个判断语句来赋初值,交上去,又A了,然后无压力rank 1。接下来刷评论,发现第一题居然可以倒着来,然后公比还可能不是整数(虽然后来加了这个限制),但是我在想题时居然根本没有考虑过这两个东西,改了第一题 重新交,掉了100多分。然后搞第三题,一开始没有思路,后来知道每个点被操作次数的奇偶性是确定就会做了。然后开始码,不知道为什么,还是很紧张,这根本没人A啊,紧张个毛线啊,然后一交,RE,看代码,回溯时忘记退栈,再交,WA了,出个全是1的数据,居然没输出0,再看,有个地方写反了,再交,还是WA,这时候有公告说建议long double,又改成long double,再交才A了。最后hack的时候还挂了两发,程序都没看清楚hack什么啊。
最后第二题FST了,很显然在k=1的时候我的程序会萎掉,因为f的初值是0。然后就光荣的掉了rating,掉出了leader board。。这真是极惨的。
总结
(掉rating是好事,jcvb也会掉rating。。)做比赛不仅仅比拼知识,很多时候心态决定成败。比如说那场TC,假如我一开始冷静下来,考虑找循环节的程序的编码难度,而不是浪费时间想其他东西,可能整场比赛就会顺很多。其次,最后的时间,就应该选定一题,不再考虑另外一题,不需要担心假如自己另外一题会怎么办,相信自己的决定,不要贪心。
然后在打代码时,把编码速度慢下来,打快几分钟赢的罚时还没你FST的代价高,所以尽量在打程序时就应该把细节写好。在打完一道题时,不要急着交,先看一遍程序,然后可以适当测试一些边角,极限,已经知道答案的数据(假如思路正确的话对拍估计没什么必要),确认无误后再提交。
最后附个SRM 701的简略题解吧。。
SRM 701
PartisanGame
暴力求前10^6的dp值。然后每个位置把他前5个位置的双方胜利情况存下来,总共2^10种不同状态,找到循环节后直接计。非常好打
#include <bits/stdc++.h>
using namespace std;
bool f[100005][2];
int sav[1 << 10];
class PartisanGame
{
public:
string getWinner(int n, vector<int> a, vector<int> b)
{
f[0][0] = 1,f[0][1] = 0;
for(int i = 1;i <= n;i ++)
{
f[i][0] = 1,f[i][1] = 0;
for(auto j : a)
if (i >= j) f[i][0] &= f[i - j][1];
for(auto j : b)
if (i >= j) f[i][1] |= f[i - j][0];
if (i >= 100)
{
int mask = 0;
for(int j = 1;j <= 5;j ++) mask = (mask << 1) | (f[i - j][0]);
for(int j = 1;j <= 5;j ++) mask = (mask << 1) | (f[i - j][1]);
if (sav[mask])
{
int l = sav[mask],len = i - sav[mask],loop = max(0,(n - i) / len - 2);
n -= len * loop;
} else sav[mask] = i;
}
}
return f[n][0] ? "Bob" : "Alice";
}
};
KthStringAgain
可以观察(分析)到题目的操作相当于把一个子序列抽出来,顺序不变,剩下的东西翻转接到后面去。然后我们逐位确定答案,求方案数时dp,f[i][j]表示考虑到第i个位置,有j个位置是属于被抽出来的子序列的,最后的串和我们枚举的答案是匹配的方案数。每个位置最后具体在哪里是可以通过状态确定出来的。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pi;
typedef pair<ll,ll> pl;
class KthStringAgain
{
public:
string ss;
ll calc(string out)
{
static ll f[55][55];
memset(f,0,sizeof f);
f[0][0] = 1;
int m = out.size(),n = ss.size();
for(int i = 0;i < n;i ++)
for(int j = 0;j <= i;j ++)
if (f[i][j])
{
if ((j < m && ss[i] == out[j]) || j >= m)
f[i + 1][j + 1] += f[i][j];
int np = n - (i - j) - 1;
if ((np < m && ss[i] == out[np]) || np >= m)
f[i + 1][j] += f[i][j];
}
ll ans = 0;
for(int j = 0;j <= n;j ++) ans += f[n][j];
return ans;
}
string getKth(string s, long long k)
{
ss = s;
string out = "";
int n = s.length();
for(int i = 0;i < n;i ++)
for(char c = 'a';c <= 'z';c ++)
{
string bak = out;
out = out + c;
ll v = calc(out);
if (v >= k) break;
k -= v;
out = bak;
}
return out;
}
};
FibonacciStringSum
首先,考虑最终的答案
xayb
,因为满足
x+y=n
,所以可以变成
所以只要我们求出 ∑x0...∑xa+b 就好了。考虑dp,设 f[i][0][j] 表示 i 这个位置放的是
很显然, f 的转移可以写成矩阵的形式,那么矩阵就是
#include <bits/stdc++.h>
using namespace std;
const int mo = int(1e9) + 7;
struct mat
{
int a[105][105],n;
int* operator[](int x)
{
return a[x];
}
void init()
{
n = 102;
memset(a,0,sizeof a);
}
void set_I()
{
for(int i = 0;i < n;i ++) a[i][i] = 1;
}
};
mat operator *(mat &a,mat &b)
{
mat tmp;
tmp.init();
for(int i = 0;i < a.n;i ++)
for(int k = 0;k < a.n;k ++)
if (a[i][k])
for(int j = 0;j < a.n;j ++)
if (b[k][j])
tmp[i][j] = (tmp[i][j] + a[i][k] * 1ll * b[k][j]) % mo;
return tmp;
}
int c[55][55];
class FibonacciStringSum
{
public:
mat trans,fir;
int get(int n,int a,int b)
{
for(int i = 0;i <= 50;i ++)
{
c[i][0] = 1;
for(int j = 1;j <= i;j ++)
c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % mo;
}
trans.init(),fir.init();
for(int i = 0;i <= 50;i ++)
{
trans[i][i + 51] = 1;
for(int j = 0;j <= i;j ++)
trans[j][i] = c[i][j],trans[j + 51][i] = c[i][j];
}
fir[0][0] = 1;
int bn = n;
for(;n;n >>= 1)
{
if (n & 1) fir = fir * trans;
trans = trans * trans;
}
int ans = 0;
for(int i = 0,coef = 1;i <= b;i ++,coef = coef * 1ll * bn % mo)
{
int v = (fir[0][b - i + a] + fir[0][b - i + a + 51]) % mo;
v = v * 1ll * coef % mo * c[b][i] % mo;
if ((b - i) & 1) v = (mo - v) % mo;
ans = (ans + v) % mo;
}
return ans;
}
};