省选模拟赛 厌世者打击(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\n",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\n",ans);
    }

    return 0;
}

 

posted @ 2018-04-04 14:26  zbtrs  阅读(867)  评论(1编辑  收藏  举报