CodeForces 23E ,77C,455A,437E,245H

五天每天刷了一dp

CodeForces 455A  Boredom  

定义 :dp[i]为取前i个元素后得到的最大值。则dp[i]=max(dp[i-1],dp[i-2]+a[i]*i);

写的时候愚蠢的分类讨论i元素是否选取。实际上第i-2个元素是否选取和状态dp[i]无关

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define ll __int64
const int maxn=100000;
ll a[maxn+8];
ll  dp[maxn+8][2];
int main()
{
    int i,j,k,n;
    scanf("%d",&n);
    memset(a,0,sizeof(a));
    memset(dp,0,sizeof(dp));
    for(i=1;i<=n;i++)
    {
        scanf("%d",&k);
        a[k]++;
    }
    int x,y;
    for(i=1;i<=maxn;i++)
    {
        if(a[i]==0)
            dp[i][1]=max(dp[i-1][1],dp[i-1][0]);
        else
            dp[i][1]=max(dp[i-1][0]+a[i]*i,dp[i-1][1]);
        dp[i][0]=dp[i-1][1];
    }
    printf("%I64d\n",dp[maxn][1]);
    return 0;
}

CodeForces 245H  Queries for Number of Palindromes

给定一个字符串,q个询问,每个询问这个区间内有多少个回文串

区间dp统计数目即可

定义dp[i][j]为i到j的回文串总数

若s[i]==s[j]并且i+1~j-1段为回文串  dp[i][j]=dp[i][j-1]+dp[i+1][j]-dp[i+1][j-1]+1;

否则dp[i][j]=dp[i][j-1]+dp[i+1][j]-dp[i+1][j-1];

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=5008;
char s[maxn];
int dp[maxn][maxn];
bool papa[maxn][maxn];
int main()
{
        int q;
    int i,j,k,n,m;
     scanf("%s",s+1);
     int len=strlen(s+1);
     memset(dp,0,sizeof(dp));
     memset(papa,false,sizeof(papa));
     for(i=1;i<=len;i++)
     {    dp[i][i]=1;papa[i][i]=true;}
     for(i=1;i<len;i++)
     {
         if(s[i]==s[i+1])
         {
             dp[i][i+1]=3;
             papa[i][i+1]=true;
         }
         else
             dp[i][i+1]=2;
             }
     for(k=2;k<len;k++)
     {
         for(i=1;i+k<=len;i++)
         {
             if(s[i]==s[i+k]&&papa[i+1][i+k-1]==true)
             {
             dp[i][i+k]=dp[i][i+k-1]+dp[i+1][i+k]+1-dp[i+1][i+k-1];
             papa[i][i+k]=true;
            }
             else    dp[i][i+k]=dp[i][i+k-1]+dp[i+1][i+k]-dp[i+1][i+k-1];
         }
    }
     scanf("%d",&q);
     while(q--)
     {
         scanf("%d%d",&n,&m);
         printf("%d\n",dp[n][m]);
     }
     return 0;
}

CodeForces 437E  The Child and Polygon

给定一个多边形求在题目条件下分割方式一共有多少种

依然区间dp统计个数.先把点都化成顺时针,若i,j之间的点k满足向量jk在向量ji的顺时针方,则dp[i][j]+=dp[i][k]*dp[k][j];

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll __int64
const int maxn=208;
const int mod=1e9+7;
struct poi{
    ll x,y;
    ll operator * (const poi &a)    const
    {
        return x*a.y-y*a.x;
    }
    poi operator - (const poi &a)    const
    {
        poi u;
        u.x=x-a.x;
        u.y=y-a.y;
        return u;
    }
}f[maxn];
ll dp[maxn][maxn];
ll    medp(int x,int y)
{
    if(dp[x][y]!=-1)    return dp[x][y];
    if(y-x==1)    return dp[x][y]=1;
    ll ans=0;
    for(int i=x+1;i<y;i++)
        if((f[x]-f[y])*(f[i]-f[y])>0)
            ans=(ans+medp(x,i)*medp(i,y))%mod;
    dp[x][y]=ans;
    return ans;
}
int main()
{
    int i,j,n;
    scanf("%d",&n);
    for(i=1;i<=n;i++)
        scanf("%I64d%I64d",&f[i].x,&f[i].y);
    ll ans=0;
    for(i=1;i<n;i++)
    {
        ans+=f[i]*f[i+1];
    }
    ans+=f[n]*f[1];
    if(ans<0)
    {
        poi shit;
        for(i=1;i<=(n>>1);i++)
        {
            shit=f[i];
            f[i]=f[n-i+1];
            f[n-i+1]=shit;
        }
    }
    memset(dp,-1,sizeof(dp));
    medp(1,n);
    printf("%I64d\n",dp[1][n]);
    return 0;
}

CodeForces 77C  Beavermuncher-0xFF

没想到用优先队列优化。代码不贴了。

CodeForces 23E Tree 

对于弱的神题,——
看了某神牛的代码,高精度模板很漂亮

主算法竟然一个后序遍历思想解决,学习了

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int mod=10000;
const int st=80;
const int maxn=710;
const int maxm=2010;
int pre[maxm],last[maxm],other[maxm],s[maxm];
int tot,n;
struct bigint{
    int a[st],n;
    bigint(){
    };
    bigint(int x)
    {
        memset(a,0,sizeof(a));
        n=1,a[0]=x;
    }
    void init(int x)
    {
        n=1,a[0]=x;
    }
    bool operator<(const bigint &x)
    {
        if(n<x.n)    return 1;
        else    if(n>x.n)    return 0;
        for(int i=n-1;i>=0;i--)
            if(a[i]<x.a[i])    return 1;
            else    if(a[i]>x.a[i])    return 0;
        return 0;
    }
    bigint operator * (const bigint &x)
    {
        bigint t(0);t.n=x.n+n-1;
        for(int i=0;i<n;i++)
            for(int j=0;j<x.n;j++)
                t.a[i+j]+=a[i]*x.a[j];
        for(int i=0;i<t.n;i++)
        {
            t.a[i+1]+=t.a[i]/mod;
            t.a[i]%=mod;
        }
        if(t.a[t.n])    t.n++;
        return t;
    }
    bigint operator + (const bigint x)
    {
        bigint t(0);t.n=max(x.n,n);
        for(int i=0;i<t.n;i++)
        {
            t.a[i]=t.a[i]+x.a[i]+a[i];
            t.a[i+1]+=t.a[i]/mod;
            t.a[i]%=mod;
        }
        if(t.a[t.n])    ++t.n;
        return t;
    }
    void print(){
        printf("%d",a[n-1]);
        for(int i=n-2;i>=0;i--)
            printf("%04d",a[i]);
        puts(" ");
    }
}dp[maxn][maxn];
void add(int p,int q)
{
    pre[++tot]=last[p];
    last[p]=tot;
    other[tot]=q;
}
void dfs(int i,int f)
{
    s[i]=1,dp[i][1].init(1),dp[i][0].init(0);
    for(int j=last[i];j;j=pre[j])
    {
        int k=other[j];
        if(k==f)    continue;
        dfs(k,i);
        for(int p=s[i];p>=0;p--)
        {
            for(int q=s[k];q>=0;q--)
            {
                bigint c=dp[i][p]*dp[k][q];
                if(dp[i][p+q]<c)    dp[i][p+q]=c;
            }
        }
        s[i]+=s[k];
    }
    for(int p=1;p<=s[i];p++)
    {
        bigint c(p);
        c=c*dp[i][p];
        if(dp[i][0]<c)    dp[i][0]=c;
    }
}
int main()
{
    int i,j,u,v;
    scanf("%d",&n);
    for(i=1;i<n;i++)
    {
        scanf("%d%d",&u,&v);
        add(u,v);add(v,u);
    }
    dfs(1,0);
    dp[1][0].print();
    return 0;
}
时间: 2024-10-11 22:44:17

CodeForces 23E ,77C,455A,437E,245H的相关文章

Codeforces 23E Tree(树型DP)

题目链接 Tree dp[x][i]表示以x为根的子树中x所属的连通快大小为i的时候 答案最大值 用dp[x][j] * dp[y][k] 来更新dp[x][j + k]. (听高手说这类题的套路其实都差不多) 因为这题输出数据会很大所以用Java-- QAQ 1 import java.util.*; 2 import java.io.*; 3 import java.math.*; 4 5 public class Main{ 6 static final int maxn = 710; 7

[Codeforces 23E] Tree

Brief Intro: 一棵树,删去若干条边,最大化得到的所有连通块大小的乘积 Algorithm: 这其实算是一类题型吧,虽然这是我做的第一题 树形DP,维护关于子树根节点的信息 此处用dp[i][s],表示以i为根的子树,且i所属连通块的大小为s时的最大值 转移时还是树形DP的常规套路,用类似背包的形式转移:dp[i的孩子][k]*dp[i][s]  ------->   dp[i][k+s] 需要注意的是,此题需要高精度,写一个Big Integer模板类即可 Code: #includ

练习赛44

练习赛44 Begin: 2019-04-03 18:35 PDD:355rlb A Kefa and Park CodeForces 580C 标签:暴力dfs(55) 题目大意: ? 一棵以1为根的树,树上有些点是红的.一个叶子是合法的当且仅当从根到它的路径上出现的连续红点个数不超过m.求有多少个叶子是合法的. 思路: 直接搜索就可以了,注意细节. CODE: #include<bits/stdc++.h> using namespace std; const int N=1e5+5; b

codeforces 245H H. Queries for Number of Palindromes(区间dp)

题目链接: codeforces 245H 题目大意: 给出一个字符串,询问任意区间内的回文子串的个数. 题目分析: 定义isPar[i][j]表示区间字符串[i,j]是否是回文,可以通过isPar[i+1][j-1]递推得到. 定义dp[i][j]表示及区间[i,j]内的回文子串的个数,转移方程如下: dp[i][j]=dp[i+1][j]+dp[i][j?1]?dp[i+1][j?1]+isPar[i][j] 用到了一点容斥的思想. AC代码: #include <iostream> #i

Codeforces 437E The Child and Polygon(区间DP)

题目链接:Codeforces 437E The Child and Polygon 题目大意:给出一个多边形,问说有多少种分割方法,将多边形分割为多个三角形. 解题思路:首先要理解向量叉积的性质,一开始将给出的点转换成顺时针,然后用区间dp计算.dp[i][j]表示从点i到点j可以有dp[i][j]种切割方法.然后点i和点j是否可以做为切割线,要经过判断,即在i和j中选择的话点k的话,点k要在i,j的逆时针方. #include <cstdio> #include <cstring&g

Codeforces 77C 树形dp + 贪心

题目链接:点击打开链接 题意: 给定n个点, 每个点的豆子数量 下面是一棵树 再给出起点 每走到一个点,就会把那个点的豆子吃掉一颗. 问:回到起点最多能吃掉多少颗豆子 思路:树形dp 对于当前节点u,先把子节点v都走一次. 然后再往返于(u,v) 之间,直到u点没有豆子或者v点没有豆子. dp[u] 表示u点的最大值.a[u] 是u点剩下的豆子数. #include <cstdio> #include <vector> #include <algorithm> #inc

Codeforces 455A Boredom (dp)

很裸的dp 状态转移方程 dp[i]=max(dp[i-1],dp[i-2]+dp[i]*i) #include<bits/stdc++.h> using namespace std; long long dp[100020]; int main() { int n,a; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a); dp[a]++; } for(int i=2;i&

Codeforces 455A Boredom 取数字的dp

题目链接:点击打开链接 给定一个n长的序列 删除x这个数就能获得x * x的个数 的分数,然后x+1和x-1这2个数会消失,即无法获得这2个数的分数 问最高得分. 先统计每个数出现的次数,然后dp一下,对于每个数只有取或不取2种状态. #include <algorithm> #include <cctype> #include <cassert> #include <cstdio> #include <cstring> #include <

dp --- Codeforces 245H :Queries for Number of Palindromes

Queries for Number of Palindromes Problem's Link:   http://codeforces.com/problemset/problem/245/H Mean: 给你一个字符串,然后q个询问:从i到j这段字符串中存在多少个回文串. analyse: dp[i][j]表示i~j这段的回文串数. 首先判断i~j是否为回文,是则dp[i][j]=1,否则dp[i][j]=0; 那么dp[i][j]=dp[i][j]+dp[i][j-1]+dp[i+1[j