zoukankan      html  css  js  c++  java
  • Codeforces 840C 题解(DP+组合数学)

    题面

    传送门:http://codeforces.com/problemset/problem/840/C
    C. On the Bench
    time limit per test2 seconds
    memory limit per test256 megabytes
    inputstandard input
    outputstandard output
    A year ago on the bench in public park Leha found an array of n numbers. Leha believes that permutation p is right if for all 1 ≤ i < n condition, that api·api + 1 is not perfect square, holds. Leha wants to find number of right permutations modulo 109 + 7.

    Input
    First line of input data contains single integer n (1 ≤ n ≤ 300) — length of the array.

    Next line contains n integers a1, a2, … , an (1 ≤ ai ≤ 109) — found array.

    Output
    Output single integer — number of right permutations modulo 109 + 7.

    Examples
    inputCopy
    3
    1 2 4
    outputCopy
    2
    inputCopy
    7
    5 2 4 2 4 1 1
    outputCopy
    144
    Note
    For first example:

    [1, 2, 4] — right permutation, because 2 and 8 are not perfect squares.

    [1, 4, 2] — wrong permutation, because 4 is square of 2.

    [2, 1, 4] — wrong permutation, because 4 is square of 2.

    [2, 4, 1] — wrong permutation, because 4 is square of 2.

    [4, 1, 2] — wrong permutation, because 4 is square of 2.

    [4, 2, 1] — right permutation, because 8 and 2 are not perfect squares.
    中文题目大意:
    给出n个正整数数,求将n个数排列成相邻两个数之积不是完全平方数的序列的方法数,结果模1000000007

    分析

    此题是一道综合性题目,考察了DP,组合数学和数论知识
    我们先从DP入手
    在DP之前,要做一个预处理,将n个数分成size组,每组中的数相乘为完全平方数,与其他数乘起来不能得到完全平方数的数单独一组
    如1 4 2 5 9 可以分为{1.4.9},{2},{5}三组

    接着开始推导DP方程
    分解子状态:设dp[i][j] 表示前i组数中有j个不合法的数对时的方法数(一个不合法数对即两个数乘起来是完全平方数,如1,9)
    设第i组有cnt个数,前i组一共有sum个数
    第i组数的顺序可以任意排列,有cnt!种排法
    我们将第i组分为k段,则产生了k个不合法的序列,分为s段的方法数为C(cnt-1,k-1) .可以这样想象,在第i组数中间的cnt-1个间隔中,插入k-1个隔板,把cnt个数分为k段

    从前面j个数对不合法的中选p个数对,有C(j,p)种方法,将k组数中的p组插入到数对中,使每个数对中间有一组数,这样就消除了p个不合法数对
    如数对(1,4) 可以用插入数对(5,20)来消除
    数列变成5,1,20,4

    k组数中的另外(k-p)组数则另外选位置插入。在sum+1个可插入的位置(头尾也可以插入),原来不合法的j个空缺不能插入,因此只能插入到sum+1-j个位置,有C(sum+1-j,k-p)种方法,这s-p组数本身是不合法的。
    原本这cnt个数连续排在一起是不合法的,会产生cnt-1个不合法数对,但我们用k-1个隔板隔开后,有k-1个位置变成合法的了,每组数因此又会产生cnt-k个不合法位置
    如:1 4 9 ,分为{1,4},{9}插入到序列A,B,C中
    A 1 4 B 9 C ,有1个位置不合法,即1,4

    这样插入过后,消除了p个不合法数对,新增了cnt-k个不合法数对,总不合法数对个数为j-p+cnt-k个
    于是我们就实现了从dp[i-1][j]到dp[j-p+cnt-k]的转移
    状态转移方程为:
    dp[i][jp+cntk]=dp[i][jp+cntk]+cnt!×dp[i1][j]×Ck1cnt1×Cpj×Ckpsum+1jdp[i][j−p+cnt−k]=dp[i][j−p+cnt−k]+cnt!×dp[i−1][j]×Ccnt−1k−1×Cjp×Csum+1−jk−p

  • 相关阅读:
    java中的Set的使用以及各种遍历方法(较为全面)
    系统图标
    监听按钮
    GUI
    【Avalon】获取隐藏元素的尺寸
    Hooks
    特性节点Attribute
    ngCloak
    邮件
    时间
  • 原文地址:https://www.cnblogs.com/birchtree/p/9845846.html
Copyright © 2011-2022 走看看