• 省选模拟赛 厌世者打击(60分)


    分析:码死我了这道题......

       第一次用矩阵树定理+高斯消元做题. O(n^3)可以跑过前50%的点. 对于k = 1的点,直接输出1即可.关键是有一个取模操作......

       一开始我用double存答案,因为最后要取绝对值,取模的话不好弄,干脆用double就能不取模了. 打完之后要存到long long中,发现会爆掉,于是用fmod函数取模,发现结果又不对.

       正确的做法是利用行列式变换的性质. 行列式的两行交换会使答案取反,那么ans = -ans即可. 行列式的一行取反也会使得答案取反. 为了保证最后取模得到的结果是正确的. 需要保证高斯消元数组a中的每个元素都是 < mod并且 ≥ 0的. 当要消第i个元素时,将这一行全部取模. 如果其<0,则将这一行全部反转. 再来消. 每消一次就要换行一次.(有点类似于更相减损术中的大数-小数),答案也跟着变.这样利用long long就能存下答案了.

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    typedef long long ll;
    const ll mod = 1e9+7;
    const double eps = 1e-9;
    double d[1010][1010],c[1010][1010];
    ll n,k,ans,a[1010][1010];
    
    void solve()
    {
        n--;
        ans = 1;
        for (int i = 1; i <= n; i++)
        {
            if (a[i][i] < 0)
            {
                for (int k = i; k <= n; k++)
                    a[i][k] = -a[i][k];
                ans = -ans;
            }
            for (int j = i + 1; j <= n; j++)
            {
                for (int k = i; k <= n; k++)
                    a[i][k] %= mod,a[j][k] %= mod;
                while (a[j][i])
                {
                    if (a[j][i] < 0)
                    {
                        for (int k = i; k <= n; k++)
                            a[j][k] = -a[j][k];
                        ans = -ans;
                    }
                    ll t = a[i][i] / a[j][i];
                    for (int k = i; k <= n; k++)
                        a[i][k]=(a[i][k]-t*a[j][k]+mod)%mod;
                    for (int k = i; k <= n; k++)
                        swap(a[i][k],a[j][k]);
                    ans = -ans;
                }
            }
            ans = ans * a[i][i] % mod;
        }
        ans = (ans % mod + mod) % mod;
    }
    
    int main()
    {
        scanf("%lld%lld",&n,&k);
        if (k == 1)
            printf("%d
    ",1);
        else
        {
            for (int i = 2; i <= n; i++)
            {
                for (int j = 1; j <= k; j++)
                {
                    int t = i - j;
                    if (t <= 0)
                        break;
                    d[i][i]++;
                    d[t][t]++;
                    c[i][t]++;
                    c[t][i]++;
                }
            }
            for (int i = 1; i <= n; i++)
                for (int j = 1; j <= n; j++)
                    a[i][j] = d[i][j] - c[i][j];
            solve();
            printf("%lld
    ",ans);
        }
    
        return 0;
    }
  • 相关阅读:
    第二次:Ubuntu16.04 安装Docker
    第一次:从今开始玩Linux,Ubuntu16.04
    学习日常
    Vector和ArrayList的异同、Hashtable和HashMap的异同
    如何吃透Python的面向对象(OOP)
    Python基础(下篇)
    Python基础(中篇)
    Python基础(上篇)
    Pycharm安装
    Python的安装与配置
  • 原文地址:https://www.cnblogs.com/zbtrs/p/8717056.html
Copyright © 2020-2023  润新知