SDOI2015 Round1总结

SDOI2015 Round1总结

这次总体上考出了自己的水平。但还是有做的不足的地方。

做题过程

  • 一开始先看了题目,发现第二,三题看起来比较水。然后第一题刚看懂题意就开始放弃了。

  • 第二题因为之前做过类似的题目,于是就马上想到了带权重心。纠结了差不多一个多钟应该要怎么点剖来维护答案。结果没有YY出来。此时只剩下3个半钟,马上去敲了第三题。

  • 第三题和MX的组合数的主体思想几乎一模一样,所以花了大概1个钟左右的时间就打完了暴力和程序,但是FFT一开始居然还打错了,调了一会儿才调出来。对于FFT还是太不熟悉。

然后我就一直在纠结第二题!!!!
  • 再打第二题时,因为有点心急,就马上打了了LCT准备骗分,结果连骗分都没有想好。然后我忽然发现自己太过急躁,马上冷静下来。望着我的暴力半天,结果想到了一个复杂度还算可以的算法。。打完又拍完之后就只剩半个钟了。

  • 本来我还想把第一题的暴力也打了。但是我计算了一下我的算法的复杂度。自我感觉过不了,然后就没有打了。。。。。结果。事实证明这是能拿30分的。。

最后总分200。。。。切了后两题。

暴露的主要问题。

  • 遇到一个与之前做过差不多的题,总是会不由自主的往那个方向去想。容易导致自己走入弯路。
  • 当一道自己觉得比较水的题目调不出来的时候,容易变得心急。然后问题就被自己无限放大了。。
  • 把自己会做的题目调对的时候会变得十分激动。其他题目就容易对自己的做法分析错误,导致不应该的失分。

改正方向

  • 敲代码前一定要想清楚,不能太心急。要让自己平静下来。
  • 不会做的题目一定要打暴力,尽量拿分。
  • 在暴力程序中适当加上一些要依赖数据的算法有时候会跑得更多的分数。

GDOI BLESS!!!



题解

第一题
  • 我们可以发现对于一种合法操作序列,我们对于他的全排列都是合法的。所以我们可以从小到大操作来枚举。
    假设当前的分块是这样
    A1|A2|A3|A4|A5|A6|A7|A8
    我们将相邻两个块连成一个大块。
    A1 A2|A3 A4|A5 A6|A7 A8

    可以发现对于处在同一个大块当中的两个小块,他们只可能在当前被交换。
    我们定义两个相邻小块|A1A2…An|An+1An+2….An+2^k|的不合法为
    An + 1 ≠ An+1.
    那么假设我们现在有k个大块中的两个小块不合法,我们分类讨论。

    1. k = 0,也就是说对于我们当前这种分块我们不需要进行操作。
    2. k = 1,只有一个大块中的两个小块需要交换,我们尝试交换,若合法我们继续递归。
    3. k = 2
      |a1a2| |a3a4|
      我们尝试交换a1,a3或a1,a4或a2,a3,或a2,a4,若合法,我们继续递归。
    4. k > 2,不可能合法
      就这样,我们就可以得到一个O(2^N * N)复杂度的算法。
第二题
  • 这题是我花的时间最多的题目了。
    可以发现的一个性质是我们的出发点必定为有效点中随意一个点。
    那现在的问题就只是怎么计算从一个点出发回到这个点的答案了。

    我们先考虑以1为根时的答案。设其为F1
    若我们现在一个操作为add(u)[Del(u)是等价的].
    我们设j为u的祖先中,深度最小的,满足Size(j)=0的点。Size(x)表示x的子树中有效点的数量。
    那么我们add(u)之后,j->u上的所有边都会对F1做出贡献。
    维护好F1后,我们考虑怎么求Fv
    假如我们当前是从Fu->Fv,v是u的儿子。

    1. Size(v) ≠ 0,那么Fv = Fu - 2 * e(u,v)
    2. Total≠Size(v),Total表示总共的有效点,那么Fv = Fu + 2 * e(u,v)
      我们肯定是从1一直转移到v的,我们可以用与求F1同样的方法来求Fv.
      先考虑情况1,二分出深度最小的满足Size(j)=0的点j,那么从1->fa(j)上的所有边都要被减去。
      再考虑情况2,二分出深度最小的满足Size(j)≠Total的j,那么从j->v上的所有边都要被加上。
      问题被完美解决。时间复杂度O(Nlog^2N)[当然,假如你愿意打LCT,时间复杂度可以少个log]
第三题

这里写图片描述
这里写图片描述

贴代码

T1
   #include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

const int MAXN = 15,MAXM = 10005;

bool ch[MAXM];
int Na[MAXM],P[MAXN],Pow[MAXN],Fac[MAXN],N,Len;
long long Ans;

void Dfs(int Now,int L)
{
    if (Now == N) {Ans += Fac[L];return;}
    int False = 0,xp = -1,yp = -1;
    for(int i = 0;i < Len / Pow[Now + 1];i ++)
    {
        int fi = i * Pow[Now + 1] + 1,fx = fi + Pow[Now];
        if (Na[fi + Pow[Now] - 1] - Na[fx] != -1) 
        {
            False ++;
            if (xp == -1) xp = i; else yp = i;
        }
    }
    if (False > 2) return;
    if (!False) Dfs(Now + 1,L); else
    {
        if (False == 1)
        {
            int fi = xp * Pow[Now + 1] + 1,fx = fi + Pow[Now];
            for(int j = 1;j <= Pow[Now];j ++) swap(Na[fi + j - 1],Na[fx + j - 1]);
            if (Na[fi + Pow[Now] - 1] - Na[fx] == -1) Dfs(Now + 1,L + 1);
            for(int j = 1;j <= Pow[Now];j ++) swap(Na[fi + j - 1],Na[fx + j - 1]);
        } else
        {
            int p[4][2];
            p[0][0] = xp * Pow[Now + 1] + 1,p[1][0] = p[0][0] + Pow[Now],p[2][0] = yp * Pow[Now + 1] + 1,p[3][0] = p[2][0] + Pow[Now];
            for(int i = 0;i < 2;i ++) p[i][1] = p[0][0];
            for(int i = 2;i < 4;i ++) p[i][1] = p[2][0];
            for(int i = 0;i < 2;i ++)
                for(int j = 2;j < 4;j ++)
                {

                    int fi = p[i][0],fx = p[j][0];
                    for(int k = 1;k <= Pow[Now];k ++) swap(Na[fi + k - 1],Na[fx + k - 1]);
                    if (Na[p[i][1] + Pow[Now] - 1] - Na[p[i][1] + Pow[Now]] == -1 && Na[p[j][1] + Pow[Now] - 1] - Na[p[j][1] + Pow[Now]] == -1) 
                        Dfs(Now + 1,L + 1);
                    for(int k = 1;k <= Pow[Now];k ++) swap(Na[fi + k - 1],Na[fx + k - 1]);
                }
        }
    }
}

int main()
{
    scanf("%d", &N);
    Pow[0] = 1;Fac[0] = 1;
    for(int i = 1;i <= N;i ++) Pow[i] = Pow[i - 1] * 2,Fac[i] = Fac[i - 1] * i;
    Len = Pow[N];
    for(int i = 1;i <= Len;i ++) scanf("%d", &Na[i]);
    Dfs(0,0);
    printf("%lld\n", Ans);
    return 0;
} 
T2
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<set>

using namespace std;

const int MAXN = 100005;

typedef long long LL;

struct Node
{
    int To,Next,Cost;
    Node(void){}
    Node(int a,int b,int c) : To(a),Next(b),Cost(c){}
}E[MAXN * 2];

set<int>T;
bool Tr[MAXN];
LL Deep[MAXN],High[MAXN],VSum[MAXN],F1;
int So[MAXN],L[MAXN],R[MAXN],cnt;
int V[MAXN],Size[MAXN],C[MAXN],Fa[18][MAXN],Final[MAXN],tot,N,M,Cnt;


void read(int &x)
{
    char c;
    while (c = getchar(),c < '0' || c > '9');
    x = c - 48;
    while (c = getchar(),c >= '0' && c <= '9') x = x * 10 + c - 48;
}

void Link(int u,int v,int c)
{
    E[++ tot] = Node(v,Final[u],c),Final[u] = tot;
}

void Dfs(int Now,int Pre)
{
    Fa[0][Now] = Pre;
    L[Now] = R[Now] = ++ cnt;
    High[Now] = High[Pre] + 1;
    for(int i = Final[Now];i;i = E[i].Next)
    if (E[i].To != Pre)
    {
        V[E[i].To] = 2 * E[i].Cost;VSum[E[i].To] = VSum[Now] + 2 * E[i].Cost;
        Deep[E[i].To] = Deep[Now] + E[i].Cost;
        Dfs(E[i].To,Now);
        R[Now] = R[E[i].To];
    }
}

int LCA(int a,int b)
{
    if (High[a] > High[b]) swap(a,b);
    for(int i = 17;i + 1;i --)
    if (High[Fa[i][b]] >= High[a]) b = Fa[i][b];
    if (a == b) return a;
    for(int i = 17;i + 1;i --)
    if (Fa[i][a] != Fa[i][b]) a = Fa[i][a],b = Fa[i][b];
    return Fa[0][a];
}

LL Dis(int a,int b)
{
    return Deep[a] + Deep[b] - 2 * Deep[LCA(a,b)];
}

void Modify(int p,int ad)
{
    p = L[p];
    for(;p <= N;p += p & -p) So[p] += ad;
}

int Sum(int p)
{
    int tmp = 0;
    for(;p;p -= p & -p) tmp += So[p];
    return tmp;
}

int Get_Size(int u)
{
    return Sum(R[u]) - Sum(L[u] - 1);
}

void Change(int p,int ad)
{
    int cur = p,need;bool ch = 0;
    if (ad == 1) need = 0; else need = 1;
    for(int i = 17;i + 1;i --)
    if (Fa[i][cur] && (Get_Size(Fa[i][cur]) == need)) cur = Fa[i][cur],ch = 1;
    if (Get_Size(p) != need) {Modify(p,ad);return;}
    Modify(p,ad);
    cur = Fa[0][cur];
    LL C = VSum[p] - VSum[cur];
    if (ad == 1) F1 += C; else F1 -= C;
}

LL Get_Ans(int p)
{
    int cur = p,total = Get_Size(1);
    for(int i = 17;i + 1;i --)
    if (Fa[i][cur] && (Get_Size(Fa[i][cur]) != total)) cur = Fa[i][cur];
    LL Tmp = F1;
    if (Get_Size(p) != total) Tmp += VSum[p] - VSum[Fa[0][cur]];
    cur = p;
    for(int i = 17;i + 1;i --)
    if (Fa[i][cur] && (!Get_Size(Fa[i][cur]))) cur = Fa[i][cur];
    if (!Get_Size(p)) Tmp -= VSum[Fa[0][cur]]; else Tmp -= VSum[cur];
    return Tmp;
}

int main()
{
    read(N),read(M);
    for(int i = 1;i < N;i ++)
    {
        int u,v,c;read(u),read(v),read(c);
        Link(u,v,c),Link(v,u,c);
    }
    Dfs(1,0);
    for(int i = 1;i < 18;i ++)
        for(int j = 1;j <= N;j ++) Fa[i][j] = Fa[i - 1][Fa[i - 1][j]];
    for(int i = 1;i <= M;i ++)
    {
        int p,ad = 0,top;read(p);
        if (Tr[p]) ad = -1,T.erase(T.find(p)); else ad = 1,T.insert(p);
        Change(p,ad);
        Tr[p] ^= 1;
        Cnt += ad;
        if (T.empty()) {printf("0\n");continue;}
        LL acu = 0,lst = 0;
        int Hev = *T.begin();
        printf("%lld\n", Get_Ans(Hev));
    }
    return 0;
}
T3
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

const int MAXN = 16400,Mo = 1004535809,G = 3;

typedef long long LL;
typedef LL Dp[MAXN];

Dp tp,C,Tmp,Wi,BakC;
int A[MAXN],Rev[MAXN],N,M,L,x,Len,Re,digit;

void Get_Origin(int t)
{
    int r = 0;
    for(int i = 1;i < t;i ++)
    {
        bool ok = 1;
        for(int j = 1,tmp = 1;j < t - 1;j ++)
        {
            tmp = tmp * LL(i) % t;
            if (tmp == 1) {ok = 0;break;}
        }
        if (ok) {r = i;break;}
    }
    for(int i = 0,tmp = 1;i < t - 1;tmp = (tmp * LL(r)) % t,i ++)
        Rev[tmp] = i;
}

int Fast(int a,int b,int mo)
{
    if (!b) return 1;
    LL mid = Fast(a,b / 2,mo);
    if (b & 1) return mid * mid % mo * a % mo;
    return mid * mid % mo;
}

void FFT_PREPARE()
{
    Wi[0] = 1,Wi[1] = Fast(G,(Mo - 1) / Len,Mo);
    for(int i = 2;i <= Len;i ++) Wi[i] = Wi[i - 1] * LL(Wi[1]) % Mo;
}

void DFT(Dp &a,int sig) 
{
    for(int i = 0;i < Len;i ++)
    {
        int tmp = 0;
        for(int j = i,c = 0;c < digit;c ++,j >>= 1) tmp = (tmp <<= 1) |= (j & 1);
        tp[tmp] = a[i];
    }
    for(int m = 1;m <= Len;m <<= 1)
        for(int i = 0,half = m / 2;i < half;i ++)
        {
            int w = sig > 0 ? Wi[i * Len / m] : Wi[Len - i * Len / m];
            for(int j = i;j < Len;j += m)
            {
                int u = tp[j],v = w * LL(tp[j + half]) % Mo;
                tp[j] = (u + v) % Mo;
                tp[j + half] = (u - v + Mo) % Mo;
            }
        }
    for(int i = 0;i < Len;i ++) a[i] = tp[i];
}

void Multiply(Dp &c,Dp &a,Dp &b)
{
    DFT(a,1),DFT(b,1);
    for(int i = 0;i < Len;i ++) a[i] = LL(a[i]) * b[i] % Mo;
    DFT(a,-1);
    for(int i = 0;i < Len;i ++) c[i] = LL(a[i]) * Re % Mo;
    for(int i = M - 1;i < Len;i ++)
    {
        (c[i % (M - 1)] += c[i]) %= Mo,c[i] = 0;
    }
}

int main()
{
    scanf("%d%d%d%d", &N, &M, &x, &L);
    for(Len = 1,digit = 0;Len < M * 2;Len <<= 1,digit ++);
    Re = Fast(Len,Mo - 2,Mo);
    FFT_PREPARE();
    Get_Origin(M);
    for(int i = 1;i <= L;i ++)
    {
        int p;scanf("%d", &p);
        if (p % M) C[Rev[p % M]] ++;
    }
    Tmp[0] = 1;
    /* for(int i = 1;i <= N;i ++)
    {
        for(int i = 0;i < Len;i ++) BakC[i] = C[i];
        Multiply(Tmp,Tmp,BakC);
    } */
    for(;N;N >>= 1)
    {
        for(int i = 0;i < Len;i ++) BakC[i] = C[i];
        if (N & 1) Multiply(Tmp,Tmp,BakC);
        for(int i = 0;i < Len;i ++) BakC[i] = C[i];
        Multiply(C,C,BakC);
    }
    printf("%d\n", Tmp[Rev[x]]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值