2019.9.5 bzoj(1202,1004)

女生的网名这么多〃 提交于 2019-12-03 15:22:02

2019.9.5晚刷题记录

\(1.bzoj\) \(1202\) 狡猾的商人

(类似3714 Kuglarz)

做法:带权并查集

错误原因:快读写错了

用时:40min

分析:

还是利用前缀和的思想,\(num[i,j]=sum [j]-sum [i-1]\).

如果暴力维护,不能维护到所有的信息,例:

\(num[1,3]=4 ,num[1,2]=2 ,num[2,3]=5\)是错误的,但无法判断出来,但是从这里我们发现了它们之间的关系是具有传递性的,所以我们可以考虑使用并查集。

我们记\(d[x]\)表示\(sum[x]-sum[ fa [x]]\).

首先要注意的是输入\(s,t\)时,\(--s\)

其次是需要在每次\(find\)的时候增加一些新的操作

int find(int x)
{
    if(x==fa[x]) return fa[x];
    int t=find(fa[x]);
    d[x]+=d[fa[x]];//不能写为d[x]+=d[t],因为这样中间跳过了许多步骤,我们的到新的d[x]的正确过程 
    fa[x]=t;       //应该是sum[x]-sum[fa[x]]+
    return fa[x];  //sum[fa[x]]-sum[fa[fa[x]]]+...+sum[son[t]]-sum[t]
}

另外要注意的就是在每次输入关系时,若s-1与t在同一个集合中,则直接查询\(num[s,t]=sum[t]-sum[s-1]\) (我们在输入时已经\(--s\)了,所以这里不用再\(-1\)\(=d[t]-d[s-1]\).

若两者在不同的集合中,就将它们进行合并

int fu=find(u),fv=find(v);
if(fu!=fv)
{
    fa[fv]=fu;
    d[fv]=d[u]+w-d[v];//d[fv]=sum[fv]-sum[fa[fv]]=sum[fv]-sum[fu]=sum[u]-sum[fu]-                           //sum[v]+sum[fv]+w,又因为sum[v]-sum[u]=w
    //其实并不需要关心是fu大还是fv大,因为这样的出来的结果依然是正确的,相当于是sum[1]-sum[3]=-       //(sum[3]-sum[1])
}

\(2.bzoj\) \(1004\) \(Cards\)

做法:burnside引理,polya定理,置换

错误:

因为每个排列都要重新计算不动点的个数,所以那些dp里要用到的东西基本上都要每次清零(然而我并没有)

用时:60min

坑点一:算循环节的个数,我是直接用\(tarjan\)算强联通分量的个数,然而事实是一个很简单的dfs就可以了(其实这个说不上是坑点)

int cnt=0;
for(int i=1;i<=n;++i)
{
    if(!vis[i])
    {
        int sz=0;
        while(!vis[i]) vis[i]=1,sz++,i=a[i];
        sum[++cnt]=sz;
    }
}

坑点二:实际上它不能直接上不动点的个数方程\(C(f)=kxor(m(f))\),因为这里的颜色个数是有限制的,不过解决方法也很简单,用一个三维的\(dp\)方程就可以了。

我们设\(f [i] [j] [k]\)表示红色选了\(i\)个,蓝色选了\(j\)个,绿色选了\(k\)个的方案总数,最后\(C(f)=f [sr] [sb] [sg]\)

for(int i=1;i<=cnt;++i)
{
    for(int j=sr;j>=0;--j)
    {
        for(int k=sb;k>=0;--k)
        {
            for(int h=sg;h>=0;--h)
            {
                if(j>=sum[i]) f[j][k][h]=(f[j][k][h]+f[j-sum[i]][k][h])%p;
                if(k>=sum[i]) f[j][k][h]=(f[j][k][h]+f[j][k-sum[i]][h])%p;
                if(h>=sum[i]) f[j][k][h]=(f[j][k][h]+f[j][k][h-sum[i]])%p;
            }
        }
    }
}
return f[sr][sb][sg];

坑点三:不动也是一个置换,还要算上它的不动点个数,最后是乘上\(m+1\)的逆元(其实这不算是一个坑点:所有这类的题都是这样的,会除上\((m+1)\))。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!