dp太难了

dp

给你一个长度为50的数字串,问你有多少个子序列构成的数字可以被3整除 答案对1e9+7取模

#include <bits/stdc++.h>

#define int long long
using namespace std;
//const int mod = 998244353;
const int mod = 1e9 + 7;
const int maxn = 1e6 + 10;

int dp[55][3];

void solve() {
    string t;
    cin >> t;
    int l = t.size();
    int m = 0;
    for (int i = 0; i < 55; ++i)
        dp[i][(t[i]-'0')%3] = 1;
    for (int i = 0; i < l; ++i) {
        m = (t[i] - '0') % 3;
        for (int j = 0; j < 3; ++j) {
            dp[i][j] += (dp[i - 1][j] + dp[i - 1][(j + 3 - m) % 3]) % mod;
        }
    }
    cout << dp[l - 1][0] % mod << endl;
}

signed main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int _ = 1;
//    cin >> _;
    while (_--)
        solve();
    return 0;
}


牛牛喜欢整数序列,他认为一个序列美丽的定义是

1:每个数都在0到40之间
2:每个数都小于等于之前的数的平均值
具体地说:for each i, 1 <= i < N, A[i] <= (A[0] + A[1] + … + A[i-1]) / i.
3:没有三个连续的递减的数

现在给你一个序列,每个元素是-1到40,你可以将序列中的-1修改成任意的数,求你可以得到多少个美丽序列,答案对1e9+7取模

#include <bits/stdc++.h>

//#pragma GCC optimize(2)
#define int long long
using namespace std;
//const int mod = 998244353;
const int mod = 1e9 + 7;
const int maxn = 1e3 + 10;

int a[45];
int dp[45][45][3][1605];

void solve() {
    int n;
    cin>>n;
    for (int i = 1; i <=n; ++i) cin>>a[i];
    if(a[1]==-1){
        for (int i = 0; i <=40; ++i) {
            dp[1][i][1][i]=1;
        }
    } else dp[1][a[1]][1][a[1]]=1;
    for (int i = 2; i <=n; ++i) {
        if(a[i]==-1){
            ///枚举当前数是啥
            for (int j = 0; j <=40; ++j) {
                ///枚举前一个数是啥
                for (int pj = 0; pj <=40; ++pj) {
                    for (int k = j*(i-1); k <=1600-j; ++k) {
                        if (j>=pj){
                            dp[i][j][1][k+j]=(dp[i][j][1][k+j]+dp[i-1][pj][1][k]+dp[i-1][pj][2][k])%mod;
                        } else{
                            dp[i][j][2][j+k]=(dp[i][j][2][k+j]+dp[i-1][pj][1][k])%mod;
                        }
                    }
                }
            }
        } else{
            for (int pj = 0; pj <=40; ++pj) {
                for (int k = a[i]*(i-1); k <=1600-a[i]; ++k) {
                    if (a[i]>=pj){
                        dp[i][a[i]][1][k+a[i]]=(dp[i][a[i]][1][k+a[i]]+dp[i-1][pj][1][k]+dp[i-1][pj][2][k])%mod;
                    } else{
                        dp[i][a[i]][2][a[i]+k]=(dp[i][a[i]][2][k+a[i]]+dp[i-1][pj][1][k])%mod;
                    }
                }
            }
        }
    }
    int sum=0;
    for (int j = 0; j <=1600; ++j) {
        for (int i = 0; i <=40; ++i) {
            sum=(sum+dp[n][i][1][j])%mod;
            sum=(sum+dp[n][i][2][j])%mod;
        }
    }
    cout<<sum;
}

signed main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int _ = 1;
//    cin >> _;
    while (_--) {
        solve();
    }
    return 0;
}


牛牛正在打一场CF

#include <bits/stdc++.h>

#define int long long
using namespace std;
const int maxn = 1e5 + 5;

struct node{
    int score;
    int down;
    int time;
    bool operator <(const node& yxj) const {
        return down*1.0/time>yxj.down*1.0/yxj.time;
    }
}nc[55];
int dp[maxn];

void solve() {
    int n,m;
    cin>>n>>m;
    for (int i = 0; i < n; ++i)
        cin>>nc[i].score;
    for (int i = 0; i < n; ++i)
        cin>>nc[i].down;
    for (int i = 0; i < n; ++i)
        cin>>nc[i].time;
    sort(nc,nc+n);
    int max_=0;
    for (int i = 0; i < n; ++i) {
        for (int j = m; j >=nc[i].time; --j) {
            dp[j]=max(dp[j],dp[j-nc[i].time]+nc[i].score-nc[i].down*j);
            max_=max(max_,dp[j]);
        }
    }
    cout<<max_;
}

signed main() {
    cin.tie(), cout.tie();
    int _ = 1;
//    cin >> _;
    while (_--) {
        solve();
    }
}

给你一个数组R,包含N个元素,求有多少满足条件的序列A

使得
0 ≤ A[i] ≤ R[i]
A[0]+A[1]+…+A[N-1]=A[0] or A[1]… or A[N-1]
输出答案对1e9+9取模

数位dp

状态表示:DP[iI[j](i=62,j=1<<12)表示枚举到sum二进制的第i位时,R数组里各个数字的限制情况,这里特别解释下限制的意思,因为我们枚举SUM二进制时要考虑二进制上1的来源,设R1=10010(二进制),如果SUM的第五位是由A1的数字贡献的,既A1>=10000,那么当我们继续考虑第四位的1时,A1必然无法继续作出贡献,会导致A1超出R1的限制,直到枚举至第二位,它本身上界有1时,才能继续贡献,可是如果之前第5位的时候A1不贡献1,那么根据二进制,高位的1大于所有比它低位的1的和(10000>01111),既A1<10000,那么在考虑后面4,3,2,1位的时候,A1可以任意选择贡献1还是不贡献1,这就是限制与不限制的区别。至此J的含义已经清楚
J可以被当成一个12位的二进制数,如果第一位上是1则代表,A1是不受限制的,反之则受限,受限的Ai只能在其上届Ri有1的时候才能作出贡献。

转移方程:假设枚举到第I位,限制状态是J,如果SUM该位二进制数取0,则在该位上是1的R[i],在之后的搜索中全部变成无限制,而如果取1,1的来源有两种情况,一种是R[I]被限制了,但这一位上有1,那么R[I]依旧保持限制,其他这一位上有1的变为无限制,第二种是R[I]没被限制,那么R[I]保持无限制,其他这一位上有1的也为无限制。当然之前就已经无限制的数字在之后依旧无限制,总计三种情况,记忆化搜索。

#include <stdio.h>
#include <cstring>
#include<deque>
#include <iostream>
#include<set>

using namespace std;
const int INF = 0x3f3f3f3f;
const int mod=1e9+9;

int dp[63][1<<12];
long long R[12];
int n;
int dfs(int p,int limit){
    if(p<0) return 1;
    if(dp[p][limit]!=-1) return dp[p][limit];
    int ans=0;//用来记录第P位上有1的R[i],用于后续的限制解除.
    for(int i=1;i<=n;i++)
        if(R[i]&((long long)1<<p))
            ans|=(1<<i);
    long long res=0;
    res+=dfs(p-1,ans|limit);//如果第P位取0,所有ans记录的Ri全部解除限制ans|limit。
    for(int i=1;i<=n;i++){
        if(((long long)1<<i)&limit)//取1的时候,如果Ri已经无限制了,保持无限制,其他这一位上有1的也为无限制。当然之前就已经无限制的数字在之后依旧无限制
            res+=dfs(p-1,ans|limit);
        else if(!((1<<i)&limit)&&ans&(1<<i))//R[I]被限制了,但这一位上有1,那么R[I]依旧保持限制,其他这一位上有1的变为无限制
            res+=dfs(p-1,(ans^(1<<i))|(limit));
    }
    dp[p][limit]=res%mod;
    return dp[p][limit];
}

int main(){
    memset(dp,-1,sizeof(dp));
    cin>>n;
    for(int i=1;i<=n;i++){
        scanf("%lld",&R[i]);
    }
    dfs(61,0);
    cout<<dp[61][0]<<endl;
    return 0;
}


联合权值

#include <bits/stdc++.h>

//#pragma GCC optimize(2)
#define int long long
using namespace std;
//const int mod = 998244353;
const int mod = 1e9+7;
const int maxn = 2e5 + 10;

int w[maxn];
int max_=0,sum=0;
int p=10007;
vector<int> g[maxn];

void solve() {
    int n;
    cin>>n;
    for (int i = 1; i <n; ++i) {
        int a,b;
        cin>>a>>b;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    for (int i = 1; i <=n; ++i) {
        cin>>w[i];
    }
    for (int i = 1; i <=n; ++i) {
        int mx=0,ans=0;
        for(auto y:g[i]){
            max_=max(max_,mx*w[y]);
            sum+=ans*w[y];
            sum%=p;
            ans+=w[y];
            mx=max(mx,w[y]);
        }
    }
    cout<<max_<<" "<<(sum*2)%p<<"\n";
}

signed main() {
//    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int _ = 1;
//    cin >> _;
    while (_--) {
        solve();
    }
    return 0;
}


序列的美观度

#include <bits/stdc++.h>

#pragma GCC optimize(2)
#define int long long
using namespace std;
//const int mod = 998244353;
const int inf = 1e18;
const int mod = 1e9 + 7;
const int maxn = 2e6 + 10;
const int N = 8e7 + 10000;

int a[maxn];
int dp[maxn];

void solve() {
    int n;
    cin>>n;
    for (int i = 1; i <=n; ++i) {
        int x;
        cin>>x;
        dp[i]=max(dp[i],dp[i-1]);
        if (a[x]) dp[i]=max(dp[i],dp[a[x]]+1);
        a[x]=i;
    }
    cout<<dp[n];
}

signed main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int _ = 1;
//    cin >> _;
    while (_--) {
        solve();
    }
    return 0;
}

#include <bits/stdc++.h>
using namespace std;map<int,int>mp;
int main(){
	int n;
	cin>>n;
	int ans=0;
	mp.clear();
	for(int i=0;i<n;i++){
		int x;
		cin>>x;
		if(mp[x]){
			mp.clear();
			ans++;
		}
		mp[x]++;
	}
	cout<<ans<<endl;
}

程序员的好印象

#include <bits/stdc++.h>

#pragma GCC optimize(2)
using namespace std;
#define int long long
typedef long long LL;
typedef long long ll;
const int INF = 0x3f3f3f3f;
//const int inf = 1e18;
const int mod = 998244353;
//const int mod = 1e9 + 7;
int gcd(int a, int b) { return !b ? a : gcd(b, a % b); }

const int maxn = 1e4 + 10;
const int N = 5e5 + 100;

map<string, set<string>> ma;
multiset<int> se;
queue<int> qu;
vector<int> v;



void solve() {
    int n;
    while (cin>>n){
        int dp[maxn]={0};
        int a[maxn]={0};
        for (int i = 1,x; i <=n; ++i) {
            cin>>x,a[x]++;
            dp[i]= max(dp[i-1],a[0]-a[1]);
        }
        cout<<dp[n]+a[1]<<"\n";
    }
}

signed main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int _ = 1;
//    cin >> _;
    while (_--) {
        solve();//cout<<"\n";
    }
    return 0;
}




旅行青蛙

#include <bits/stdc++.h>

#pragma GCC optimize(2)
using namespace std;
#define int long long
typedef long long LL;
typedef long long ll;
const int INF = 0x3f3f3f3f;
//const int inf = 1e18;
const int mod = 998244353;
//const int mod = 1e9 + 7;
int gcd(int a, int b) { return !b ? a : gcd(b, a % b); }

const int maxn = 1e6 + 10;
const int N = 5e5 + 100;

map<string, set<string>> ma;
multiset<int> se;
queue<int> qu;
vector<int> v;
int a[maxn];
int dp[maxn];

void solve() {
    int n;
    cin>>n;
    for (int i = 1; i <=n; ++i) {
        cin>>a[i];
        for (int j = i-1; j >=0; j--) {
            if (a[j]<=a[i])
                dp[i]= max(dp[j]+1,dp[i]);
        }
    }
    int maxx=0;
    for (int i = 1; i <=n; ++i) {
        maxx= max(dp[i],maxx);
    }
    cout<<maxx<<"\n";
}

signed main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int _ = 1;
//    cin >> _;
    while (_--) {
        solve();//cout<<"\n";
    }
    return 0;
}




Profits

#include <bits/stdc++.h>

#pragma GCC optimize(2)
using namespace std;
#define int long long
typedef long long LL;
typedef long long ll;
const int INF = 0x3f3f3f3f;
//const int inf = 1e18;
const int mod = 998244353;
//const int mod = 1e9 + 7;
int gcd(int a, int b) { return !b ? a : gcd(b, a % b); }

const int maxn = 1e6 + 10;
const int N = 5e5 + 100;

map<string, set<string>> ma;
multiset<int> se;
queue<int> qu;
vector<int> v;
int a[maxn];
int dp[maxn];

void solve() {
    int n;
    cin>>n;
    int sum=-INF;
    for (int i = 0; i < n; ++i) {
        cin>>a[i];
        dp[i]=a[i]+dp[i-1];
        sum= max(dp[i],sum);
        dp[i]=max(dp[i],0ll);
    }
    cout<<sum<<"\n";
}

signed main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int _ = 1;
//    cin >> _;
    while (_--) {
        solve();//cout<<"\n";
    }
    return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值