Codeforces 1061C (DP+滚动数组)

题面

传送门

分析

考虑DP

设\(dp[i][j]\)表示前i个数选出的序列长度为j的方案数

状态转移方程为:

\[ dp[i][j]= \begin{cases}dp\left[ i-1\right] \left[ j-1\right] +dp\left[ i-1\right] \left[ j-1\right] ,j \equiv 0 (\mod i) \\ dp\left[ i-1\right] \left[ j-1\right],otherwise \end{cases} \]

如果二维DP,直接从1~n枚举i,j,显然会MLE

发现第一维状态i只和i-1有关,考虑用类似01背包的方法去掉一维

设dp[j]表示长度为j时的状态

第i-1次循环结束后,\(dp[j]\)存储的是原来\(dp[i-1][j]\)的值

然后我们类似01背包,倒序循环j (j为i的因数,若j不是i的因数,dp值不变,不必循环) dp[j]+=dp[j-1]

我们更新dp[j]时,dp[j-1]存的还是原来\(dp[i-1][j-1]\)的值,这样便不会重复更新

另外,因数个数怎么解决呢

我们用这样的筛法,可以在\(O(n\log n)\)的时间内筛出1~n的因数

vector<int>d[maxA];
void sieve(int x){
    for(int i=1;i<=x;i++){
        for(int j=1;j<=x/i;j++){
            d[i*j].push_back(i);
        }
    }
} 

所以总的时间复杂度为\(O(n\log \max(a_i))\)

代码

#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#define maxn 100005
#define maxA 1000005
#define mod 1000000007
using namespace std;
int n;
int maxa;
int a[maxn];
int dp[maxA];
vector<int>d[maxA];
void sieve(int x){
    for(int i=1;i<=x;i++){
        for(int j=1;j<=x/i;j++){
            d[i*j].push_back(i);
        }
    }
}
int cmp(int x,int y){
    return x>y;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        maxa=max(maxa,a[i]);
    }
    dp[0]=1;
    sieve(maxa);
    for(int i=1;i<=n;i++){
        for(int j=d[a[i]].size()-1;j>=0;j--){
            int x=d[a[i]][j];
            dp[x]+=dp[x-1];
            dp[x]%=mod;
        }
    }
    long long ans=0;
    for(int i=1;i<=n;i++){
        ans+=dp[i];
    }
    ans%=mod;
    cout<<ans;
} 

原文地址:https://www.cnblogs.com/birchtree/p/10013640.html

时间: 2024-08-30 13:45:14

Codeforces 1061C (DP+滚动数组)的相关文章

HDU 1024 Max Sum Plus Plus --- dp+滚动数组

HDU 1024 题目大意:给定m和n以及n个数,求n个数的m个连续子系列的最大值,要求子序列不想交. 解题思路:<1>动态规划,定义状态dp[i][j]表示序列前j个数的i段子序列的值,其中第i个子序列包括a[j], 则max(dp[m][k]),m<=k<=n 即为所求的结果 <2>初始状态: dp[i][0] = 0, dp[0][j] = 0; <3>状态转移: 决策:a[j]自己成为一个子段,还是接在前面一个子段的后面 方程: a[j]直接接在前面

poj3624 01背包入门 dp+滚动数组

poj3624 01背包 dp+滚动数组 Charm Bracelet Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 25458   Accepted: 11455 Description Bessie has gone to the mall's jewelry store and spies a charm bracelet. Of course, she'd like to fill it with the bes

POJ3071-Football(概率DP+滚动数组)

Football Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 2769   Accepted: 1413 Description Consider a single-elimination football tournament involving 2n teams, denoted 1, 2, -, 2n. In each round of the tournament, all teams still in the

HDU 5617 Jam&#39;s maze dp+滚动数组

题目链接: hdu: http://acm.hdu.edu.cn/showproblem.php?pid=5617 bc(中文):http://bestcoder.hdu.edu.cn/contests/contest_chineseproblem.php?cid=666&pid=1003 题解: 设dp[x1][x2][i]表示第i步时,从(1,1)点走到了(x1,y1),(n,n)点走到了(x2,y2)点的合法的总数. 1 #include<iostream> 2 #include

[ACM] HDU 4576 Robot (概率DP,滚动数组)

Robot Problem Description Michael has a telecontrol robot. One day he put the robot on a loop with n cells. The cells are numbered from 1 to n clockwise. At first the robot is in cell 1. Then Michael uses a remote control to send m commands to the ro

HDU - 2294 Pendant (DP滚动数组降维+矩阵快速幂)

Description On Saint Valentine's Day, Alex imagined to present a special pendant to his girl friend made by K kind of pearls. The pendant is actually a string of pearls, and its length is defined as the number of pearls in it. As is known to all, Ale

HDU 5119 Happy Matt Friends (背包DP + 滚动数组)

题目链接:HDU 5119 Problem Description Matt has N friends. They are playing a game together. Each of Matt's friends has a magic number. In the game, Matt selects some (could be zero) of his friends. If the xor (exclusive-or) sum of the selected friends'ma

Codeforces 712 D. Memory and Scores (DP+滚动数组+前缀和优化)

题目链接:http://codeforces.com/contest/712/problem/D A初始有一个分数a,B初始有一个分数b,有t轮比赛,每次比赛都可以取[-k, k]之间的数,问你最后A比B大的情况有多少种. dpA[i][j]表示第i轮获得j分的情况数.因为第i轮只和第i-1轮有关,所以这里i用滚动数组优化. 要是普通做法3个for就会超时,所以要用前缀和优化,dpA[i][j]可以由一段连续的dp[i - 1][x]转移过来,所以用sumA数组存取dp[i - 1][x]的前缀

Hello 2019 D 素因子贡献法计算期望 + 概率dp + 滚动数组

https://codeforces.com/contest/1097/problem/D 题意 给你一个n和k,问n经过k次操作之后留下的n的期望,每次操作n随机变成一个n的因数 题解 概率dp计算出每个素因子留下的概率,乘以这个素因子的值就是这个素因子的贡献期望 定义\(dp[i][j]\)为第i次操作后剩下j个素因子的概率,概率dp顺着推 \(dp[i][j]->dp[i+1][k](k<=j)\) \(dp[i+1][k]+=dp[i][j]\frac{1}{j+1}(k<=j)