【upc】小凯不困惑 | 结论、dp

时间限制: 1 Sec  内存限制: 256 MB
提交 状态

题目描述

现在有m+1个星球,从左到右标号为0到m,小L最初在0号星球。
有n处矿体,第i处矿体有ai单位原矿,在第bi个星球上。
由于飞船使用的是老式的跳跃引擎,每次它只能从第x号星球移动到第x+4号星球或x+7号星球。每到一个星球,小L会采走该星球上所有的原矿,求小L能采到的最大原矿数量。
注意,小L不必最终到达m号星球。

输入

第一行2个整数n,m
接下来n行,每行2个整数ai,bi。

输出

输出一行一个整数,表示要求的结果。

样例输入 Copy

3 13
100 4
10 7
1 11

样例输出 Copy

101

提示

样例解释:第一次从0到4,第二次从4到111,总共采到101单位原矿

对于 20%的数据 n=1 ,m≤105
对于 40%的数据 n≤15,m≤105
对于 60%的数据 m≤105
对于 100%的数据 n≤105,m≤109,1≤ai≤104,1≤bi≤m

提交状态

题目思路

emmm...

这题是个结论题,详见洛谷小凯的疑惑

直接来结论:如果gcd(a,b) = 1,能用ax + by  = C,使得无负整数解的最小表示的数:c = a*b - a - b

大于c一定可以表示

首先考虑合法状态:必然是可以由若干4和若干个7表示

之后进行dp,状态转移为:

如果k位置与i位置相差的距离,是有效距离(即可以用若干4和若干7表示)

\large dp[i] = (dp[k] + a[i],dp[i]) 

由此上面结论可知,最多相差17,所以可以直接向前遍历17个,之后维护前缀最大值即可。

Code:

/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(2)
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pp;
const ll INF=1e17;
const int maxn=5e5+6;
const int mod=998244353;
const double eps=1e-3;
inline bool read(ll &num)
{char in;bool IsN=false;
    in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}

ll n,m,p;
ll dp[maxn],a[maxn];
int vis[30];
struct node{
    ll x,y;
    bool friend operator<(node a,node b){
        return a.y<b.y;
    }
}q[maxn];

int judge(ll x){
    if(x>17||vis[x]) return 1;
    return 0;
}
ll pre[maxn];
map<ll,ll>mp;
int main(){
    read(n);read(m);
    for(int i=0;i*4<=17;i++){
        for(int k=0;k*7<=17;k++){
            if(i*4+k*7<=30) vis[i*4+k*7] = 1;
        }
    }
    for(int i=1;i<=n;i++){
        ll x,y;read(x);read(y);
        mp[y] += x;
    }
    int cnt = 0;
    for(auto x:mp)
        q[++cnt] = node{x.second,x.first};
    sort(q+1,q+1+cnt);
    ll ans = 0;
    for(int i=1;i<=cnt;i++){
        if(judge(q[i].y)){
            for(int k=i-1;k>=0;k--){
                ll temp = q[i].y-q[k].y;
                if(judge(temp)) dp[i] = max(q[i].x+dp[k],dp[i]);
                if(temp>17){
                    dp[i] = max(q[i].x+pre[k],dp[i]);
                    break;
                }

            }
            ans =max(ans,dp[i]);
            pre[i] = max(pre[i-1],dp[i]);
        }
        else pre[i] = pre[i-1];
    }
    printf("%lld\n",ans);
    return 0;
}
/**
3 14
10 8
7 1
2 1
**/

猜你喜欢

转载自blog.csdn.net/qq_43857314/article/details/107235175