• bzoj1494


    这道题不仅得看俞华程的论文,还得看陈丹琦的论文,否则是不可能做出来的。因为难点在构造矩阵上。

    构造矩阵困难在如何表示状态,因为树不能有环,也不能不连通,这里我们引入了最小表示法来表示连续k个点的连通性。

    首先我们找出所有可能的状态,dfs一下就行了,最多只有53种。然后计算每种状态的形态,状态只是表示了连通性,但没有表示之间的形态。于是我们初始每种状态形态的数量作为列向量。然后就是构造转移矩阵。这个转移矩阵表示一个状态能够转移到另一个状态,其实是每次向前移动一位。每次向前移动一位也就是说对于一个状态我们要找出所有可以成为这个状态后移一位的合法的状态。每两个状态之间系数矩阵上的值为可能的形态数,这里的形态数和刚才不太一样,向后移一位说明把当前k个点去掉了第一个点,然后又添加了一个点。这里我们用二进制枚举连通性,也就是说新加入的点和之前k个点中哪些点是联通的。那么这样的连通性会有很多情况,比如说原来的最小表示是001,二进制枚举出来的是11,那么新的点既要和第一个联通块联通,也要和第二个联通块联通,也就是有两种情况,即是(设这个点为4,之前为123)(4->1, 4->3) (4->2,4->3)两种联通情况。

    最后统计答案是这样做的,因为最后只有一种合法状态,即0....0,必须所有都联通,所以sigma(f[i][1]*ret[i][1]),i->1表示所有能转移到1状态的情况。

    然后就可以矩阵快速幂了。。。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 60, M = 50010, mod = 65521;
    struct mat {
        ll a[N][N];
    } A, f;
    ll k, n;
    int mir[N], cnt[N], p[N], bit[10], vis[N];
    ll power(ll x, ll t)
    {
        ll ret = 1;
        for(; t; t >>= 1, x = x * x % mod) if(t & 1) ret = ret * x % mod;
        return ret; 
    }
    void collect(int x)
    {
        int cnt[10]; memset(cnt, 0, sizeof(cnt)); f.a[p[0]][1] = 1; mir[x] = p[0];
        for(int i = 1; i <= k; ++i) ++cnt[x % 10], x /= 10;
        for(int i = 0; i < k; ++i) if(cnt[i] > 1) f.a[p[0]][1] = f.a[p[0]][1] * power(cnt[i], cnt[i] - 2) % mod;
    }
    void dfs(int num, int d, int bound, int x)
    {
        if(d == k) { p[++p[0]] = num; collect(p[p[0]]); return; }
        for(int i = 0; i <= bound; ++i) dfs(num + i * x, d + 1, max(i + 1, bound), x / 10);
    }
    void Init(int pos)
    {
        memset(bit, 0, sizeof(bit));
        int x = p[pos], maxn = -1; bool flag = true;
        for(int j = 0, l = x; j < k; ++j) bit[k - j - 1] = l % 10, l /= 10;
        for(int i = 1; i < k; ++i)
        {
            if(bit[i] == bit[0]) flag = false;
            maxn = max(maxn, bit[i]);
        } 
        int lim = 1 << (maxn + 1);
        for(int i = 0; i < lim; ++i)
        { //枚举连通性, 枚举和原来的每位是否联通 
            if(flag && !(i & 1)) continue; //不成立的情况     
            for(int j = 0, l = x; j < k; ++j) bit[k - j - 1] = l % 10, l /= 10;
            bit[k] = -1;
            int ans = 1, l = -1, tot = 0; ;        
            for(int j = 0; j <= maxn; ++j) if(i & (1 << j)) 
            { 
                int t = 0;
                for(int x = 0; x < k; ++x) if(bit[x] == j) bit[x] = -1, ++t;
                ans = ans * t;                                    
            }
            memset(vis, 0, sizeof(vis));
            for(int j = 1; j <= k; ++j) if(!vis[j])
            {
                int color = bit[j]; bit[j] = ++l; vis[j] = 1;
                for(int x = 0; x <= k; ++x) if(bit[x] == color && !vis[x]) 
                    bit[x] = l, vis[x] = 1; 
            }    
            for(int j = 1; j <= k; ++j) tot = tot * 10 + bit[j];
            A.a[pos][mir[tot]] = ans % mod;            
        }
    }
    mat operator * (mat A, mat B)
    {
        mat ret; memset(ret.a, 0, sizeof(ret.a));
        for(int i = 1; i <= p[0]; ++i)
            for(int j = 1; j <= p[0]; ++j)
                for(int k = 1; k <= p[0]; ++k) ret.a[i][j] = (ret.a[i][j] + A.a[i][k] % mod * B.a[k][j] % mod) % mod;
        return ret;        
    }
    int main()
    {
        scanf("%d%lld", &k, &n);
        if(k >= n) { printf("%lld
    ", power(n, n - 2)); return 0; }
        int base = 1; for(int i = 1; i < k; ++i) base = base * 10;
        dfs(0, 0, 0, base);
        for(int i = 1; i <= p[0]; ++i) Init(i);
        mat ret; memset(ret.a, 0, sizeof(ret.a)); for(int i = 1; i <= p[0]; ++i) ret.a[i][i] = 1;
        for(ll t = n - k; t; t >>= 1, A = A * A) if(t & 1) ret = ret * A;
        ll ans = 0;
        for(int i = 1; i <= p[0]; ++i) ans = (ans + f.a[i][1] * ret.a[i][1]) % mod;
        printf("%lld
    ", ans);
        return 0;
    }
    View Code
  • 相关阅读:
    android编译时出现org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:compileDebugJavaWithJavac'.错误
    jdk1.8中获取项目绝对路径和项目路径
    okhttp在https连接中出现java.net.ProtocolException: Expected ':status' header not present的解决办法
    mybatis+sqlserver中返回非自增主键
    华为手机不能连接android studio进行调试的解决办法
    android中service启动后台程序
    getContentLength() 指为 -1 的解决办法
    svn服务器搭建(windows)
    Caliburn.Micro 杰的入门教程3,事件和参数
    Caliburn.Micro 杰的入门教程1(翻译)
  • 原文地址:https://www.cnblogs.com/19992147orz/p/6849120.html
Copyright © 2020-2023  润新知