比较悲惨的一周

这周打了两场比赛,一场是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 ,所以可以变成

xayb=xa(nx)b=i=0b(bi)ni(1)bixa+bi

所以只要我们求出 x0...xa+b 就好了。考虑dp,设 f[i][0][j] 表示 i 这个位置放的是0 xj 是多少, f[i][1][j] 表示这个位置放的是1。那么显然,因为放1不影响答案,而且不能有两个1相邻,所以 f[i][1][j]=f[i1][0][j] ,那么对于 f[i][0][j] ,因为 (x+1)j=jk=0(jk)xk ,所以
f[i][0][j]=k=0j(jk)(f[i1][0][k]+f[i1][1][k])

很显然, f 的转移可以写成矩阵的形式,那么矩阵就是(250)(250)=100100的了,毫无压力,矩阵乘法快速幂。

#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;
    }
};
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值