CT1428 题解(待更)

A 机器人军团

典型的最长上升子序列问题,只不过这里是不下降子序列,与前者只有一个符号的区别

//#include<pch.h>
#include <iostream>
#include <cstdio>
#include <bits/stdc++.h>
#include<queue>
#include <map>
#include <algorithm>
#include <stack>
#include <iomanip>
#include <cstring>
#include <cmath>
#define DETERMINATION main
#define lldin(a) scanf_s("%lld", &a)
#define println(a) printf("%lld\n", a)
#define print(a) printf("%lld ", a)
#define reset(a, b) memset(a, b, sizeof(a))
#define debug cout<<"procedures above are available"<<endl;
using namespace std;
const int INF = 0x3f3f3f3f;
const double PI = acos(-1);
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int mod = 1000000007;
const int tool_const = 19991126;
const int tool_const2 = 33;
inline ll nextLong()
{
    ll tmp = 0, si = 1;
    char c;
    c = getchar();
    while (c > '9' || c < '0')
    {
        if (c == '-')
            si = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9')
    {
        tmp = tmp * 10 + c - '0';
        c = getchar();
    }
    return si * tmp;
}
/**Maintain your determination.Nobody knows the magnificent landscape
at his destination before the arrival with stumble.**/
/**Last Remote**/
ll datas[500000], lower[500000];
int DETERMINATION()
{
    ll n;
    n = nextLong();
    for (int i = 1; i <= n; i++)
        datas[i] = nextLong();
    fill(lower, lower + n + 1, INF);
    lower[1] = datas[1];
    ll length = 1;
    for (int i = 2; i <= n; i++)
    {
        if (datas[i] >= lower[length])
            lower[++length] = datas[i];
        else
        {
            ll location = lower_bound(lower + 1, lower + 1 + length, datas[i]) - lower;
            lower[location] = datas[i];
        }
    }
    println(length);
    return 0;
}

B 抄近路

这个题给定的是格子数,但是按照题意需要在格点上枚举状态,这里的格点会比格子多出一行一列,所以要多枚举一点。题目中给了一个反二维数列的坐标系,但是无所谓,因为这个格子地图是中心对称的,按正常二维数组下的坐标系(反Y轴第四象限)即可。(走格子对角线一定比走两条边的路程要短,这个无需判断)

//#include<pch.h>
#include <iostream>
#include <cstdio>
#include <bits/stdc++.h>
#include<queue>
#include <map>
#include <algorithm>
#include <stack>
#include <iomanip>
#include <cstring>
#include <cmath>
#define DETERMINATION main
#define lldin(a) scanf_s("%lld", &a)
#define println(a) printf("%lld\n", a)
#define print(a) printf("%lld ", a)
#define reset(a, b) memset(a, b, sizeof(a))
#define debug cout<<"procedures above are available"<<endl;
using namespace std;
const int INF = 0x3f3f3f3f;
const double PI = acos(-1);
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int mod = 1000000007;
const int tool_const = 19991126;
const int tool_const2 = 33;
inline ll nextLong()
{
    ll tmp = 0, si = 1;
    char c;
    c = getchar();
    while (c > '9' || c < '0')
    {
        if (c == '-')
            si = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9')
    {
        tmp = tmp * 10 + c - '0';
        c = getchar();
    }
    return si * tmp;
}
/**Maintain your determination.Nobody knows the magnificent landscape
at his destination before the arrival with stumble.**/
/**Last Remote**/
ll diagram[1010][1010];
const double slope = 100*sqrt(2);
ld dp[1010][1010];
int DETERMINATION()
{
    ll n, m;
    n = nextLong(), m = nextLong();
    ll k;
    k = nextLong();
    for (int i = 0; i <= n+1; i++)
        for (int j = 0; j <= m+1; j++)
            dp[i][j] = INF;
    for (int i = 1; i <= k; i++)
    {
        ll tmp1, tmp2;
        tmp1 = nextLong(), tmp2 = nextLong();
        diagram[tmp1+1][tmp2+1] = 1;
    }
    /*for (int i =n+1;i>=2; i--)
    {
        for (int j = 2; j <= m+1; j++)
        {
            cout << diagram[i][j] << " ";
        }
        cout << endl;
    }*/
    dp[1][1] = 0;
    for (int i = 1; i <=n+1; i++)
    {
        for (int j = 1; j <= m+1; j++)
        {
            if (i ==1 && j == 1)
                continue;
            if (!diagram[i][j])
                dp[i][j] = min(dp[i-1][j] + 100, dp[i][j - 1]+100);
            else
            {
                //cout << i << " " << j << endl;
                dp[i][j] = min(dp[i-1][j - 1] + slope, dp[i][j]);
            }
        }
    }
    //for (int i = 1; i <= n + 1; i++)
    //{
    //  for (int j = 1; j <= m+1; j++)
    //      cout << dp[i][j] << " ";
    //  cout << endl;
    //}
    cout << int(dp[n + 1][m + 1] + 0.5) << endl;
    return 0;
}

C 魔法矿石

这是一个典型的DAG问题,直接建图进行记忆化搜索即可,值得注意的是要把所有矿石当做起点遍历一次。

(输入格式比较特殊,故使用java)

import java.util.*;
import java.io.*;
import java.math.*;
import java.text.*;
public class Main
{
    static boolean connection[][]=new boolean[1200][1200];
    static int dp[]=new int[1200];
    static int mine[]=new int[1200]; 
    static int n;
    public static int dfs(int current)
    {
        if(dp[current]>0)
            return dp[current];
        else
        {
            dp[current]=mine[current];
            for(int i=current;i<=n;i++)
            {
                if(connection[current][i])
                {
                    dp[current]=Math.max(dp[current],dfs(i)+mine[current]);
                }
            }
            return dp[current];
        }
    }
    public static void main(String args[])throws IOException
    {
        BufferedReader bf=new BufferedReader(new InputStreamReader(System.in));
        String tmp=bf.readLine();
        n=Integer.parseInt(tmp);
        tmp=bf.readLine();
        String tmps2[]=tmp.trim().split(" ");
        for(int i=1;i<=n;i++)
            mine[i]=Integer.parseInt(tmps2[i-1]);
        for(int i=1;i<=n;i++)
        {
            tmp=bf.readLine();
            String tmps[]=tmp.trim().split(" ");
            int st=Integer.parseInt(tmps[0]);
            for(int j=1;j<tmps.length;j++)
                connection[st][Integer.parseInt(tmps[j])]=true;
        }
        int ans=0;
        for(int i=1;i<=n;i++)
            ans=Math.max(ans,dfs(i));
        System.out.println(ans);
        bf.close();
    }
}

E 友好城市

因为航线不能有交叉,所以可以假设按距离排序后某一南岸城市(以for遍历,保证递增)对应的北岸城市的位置在水平方向是递增的。所以这就变成了一个最长上升子序列的问题。

//#include<pch.h>
#include <iostream>
#include <cstdio>
#include <bits/stdc++.h>
#include <queue>
#include <map>
#include <algorithm>
#include <stack>
#include <iomanip>
#include <cstring>
#include <cmath>
#define DETERMINATION main
#pragma GCC optimize(2)
#pragma warning(disable:4996)
#define lldin(a) scanf("%lld", &a)
#define println(a) printf("%lld\n", a)
#define print(a) printf("%lld ", a)
#define reset(a, b) memset(a, b, sizeof(a))
#define debug cout<<"procedures above are available"<<endl;
#define BigInteger __int128
using namespace std;
const int INF = 0x3f3f3f3f;
const double PI = acos(-1);
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int mod = 10000000;
const int tool_const = 19991126;
const int tool_const2 = 33;
//template<typename T>
//inline BigInteger nextLong()
//{
//  BigInteger tmp = 0, si = 1;
//  char c;
//  c = getchar();
//  while (!isdigit(c))
//  {
//      if (c == '-')
//          si = -1;
//      c = getchar();
//  }
//  while (isdigit(c))
//  {
//      tmp = tmp * 10 + c - '0';
//      c = getchar();
//  }
//  return si * tmp;
//}
//std::ostream& operator<<(std::ostream& os, __int128 T)
//{
//    if (T<0) os<<"-";if (T>=10 ) os<<T/10;if (T<=-10) os<<(-(T/10));
//    return os<<( (int) (T%10) >0 ? (int) (T%10) : -(int) (T%10) ) ;
//}
//void output(BigInteger x)
//{
//  if (x < 0)
//  {
//      x = -x;
//      putchar('-');
//  }
//  if (x > 9) output(x / 10);
//  putchar(x % 10 + '0');
//}
/**Maintain your determination.Nobody knows the magnificent landscape
at his destination before the arrival with stumble.**/
/**Last Remote**/
struct node
{
    ll from, to;
}nodes[50000];
bool cmp(node a, node b)
{
    return a.to < b.to;
}
ll lower[510000];
int DETERMINATION()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    ll x, y;
    cin >> x >> y;
    ll n;
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> nodes[i].from >> nodes[i].to;
    sort(nodes + 1, nodes + 1 + n, cmp);
    ll ans = 1;
    lower[1] = nodes[1].from;
    for (int i = 2; i <= n; i++)
    {
        if (lower[ans] < nodes[i].from)
            lower[++ans] = nodes[i].from;
        else
        {
            ll loc = lower_bound(lower+1, lower+ans, nodes[i].from)-lower;
            lower[loc] = nodes[i].from;
        }
    }
    cout << ans << endl;
    return 0;
}

F 合唱队列

枚举C位所在的位置,然后在C位左边求最长上升子序列,在右边求最长下降子序列。

//#include<pch.h>
#include <iostream>
#include <cstdio>
#include <bits/stdc++.h>
#include <queue>
#include <map>
#include <algorithm>
#include <stack>
#include <iomanip>
#include <cstring>
#include <cmath>
#define DETERMINATION main
#pragma GCC optimize(2)
#pragma warning(disable:4996)
#define lldin(a) scanf("%lld", &a)
#define println(a) printf("%lld\n", a)
#define print(a) printf("%lld ", a)
#define reset(a, b) memset(a, b, sizeof(a))
#define debug cout<<"procedures above are available"<<endl;
#define BigInteger __int128
using namespace std;
const int INF = 0x3f3f3f3f;
const double PI = acos(-1);
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int mod = 10000000;
const int tool_const = 19991126;
const int tool_const2 = 33;
//template<typename T>
//inline BigInteger nextLong()
//{
//  BigInteger tmp = 0, si = 1;
//  char c;
//  c = getchar();
//  while (!isdigit(c))
//  {
//      if (c == '-')
//          si = -1;
//      c = getchar();
//  }
//  while (isdigit(c))
//  {
//      tmp = tmp * 10 + c - '0';
//      c = getchar();
//  }
//  return si * tmp;
//}
//std::ostream& operator<<(std::ostream& os, __int128 T)
//{
//    if (T<0) os<<"-";if (T>=10 ) os<<T/10;if (T<=-10) os<<(-(T/10));
//    return os<<( (int) (T%10) >0 ? (int) (T%10) : -(int) (T%10) ) ;
//}
//void output(BigInteger x)
//{
//  if (x < 0)
//  {
//      x = -x;
//      putchar('-');
//  }
//  if (x > 9) output(x / 10);
//  putchar(x % 10 + '0');
//}
/**Maintain your determination.Nobody knows the magnificent landscape
at his destination before the arrival with stumble.**/
/**Last Remote**/
ll ar[9855];
ll dp[9855];
int DETERMINATION()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    ll n;
    cin >> n;
    ll mx = -1, keyloc = 0;
    for (int i = 1; i <= n; i++)
        cin >> ar[i];
    ll ans1 = 0, ans2 = 0,finans=9999999;
    for (int keyloc = 1; keyloc <= n; keyloc++)
    {
        ans1 = 0, ans2 = 0;
        for (int i = 1; i <= n; i++)
            dp[i] = 1;
        for (int i = 2; i <= keyloc; i++)
        {
            for (int j = 1; j < i; j++)
                if (ar[j] < ar[i])
                    dp[i] = max(dp[i], dp[j] + 1);
        }
        for (int i = 1; i <= keyloc; i++)
            ans1 = max(ans1, dp[i]);
        for (int i = 1; i <= n; i++)
            dp[i] = 1;
        for (int i = keyloc + 2; i <= n; i++)
        {
            for (int j = keyloc+1; j < i; j++)
                if (ar[j] > ar[i])
                    dp[i] = max(dp[i], dp[j] + 1);
        }
        for (int i = keyloc +2; i <= n; i++)
            ans2 = max(ans2, dp[i]);
        //cout << ans1 << " " << ans2 << endl; 
        finans = min(n - (ans1 + ans2), finans);
    }
    cout <<finans<< endl;
    return 0;
}

G 简单背包问题

这题本应该有spj的,但是没有。直接dfs即可

//#include<pch.h>
#include <iostream>
#include <cstdio>
#include <bits/stdc++.h>
#include <queue>
#include <map>
#include <algorithm>
#include <stack>
#include <iomanip>
#include <cstring>
#include <cmath>
#define DETERMINATION main
#pragma GCC optimize(2)
#pragma warning(disable:4996)
#define lldin(a) scanf("%lld", &a)
#define println(a) printf("%lld\n", a)
#define print(a) printf("%lld ", a)
#define reset(a, b) memset(a, b, sizeof(a))
#define debug cout<<"procedures above are available"<<endl;
#define BigInteger __int128
using namespace std;
const int INF = 2e9 + 2;
const double PI = acos(-1);
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int mod = 1e9 + 7;
//template<typename T>
//inline BigInteger nextLong()
//{
//  BigInteger tmp = 0, si = 1;char c;  c = getchar();
//  while (!isdigit(c))
//{if (c == '-')si = -1;c = getchar();}
//  while (isdigit(c))
//  {tmp = tmp * 10 + c - '0';c = getchar();}
//  return si * tmp;    
//}         
//std::ostream& operator<<(std::ostream& os, __int128 T)
//{
//    if (T<0) os<<"-";if (T>=10 ) os<<T/10;if (T<=-10) os<<(-(T/10));
//    return os<<( (int) (T%10) >0 ? (int) (T%10) : -(int) (T%10) ) ;
//}
//void output(BigInteger x)
//{
//  if (x < 0)
//  {x = -x;putchar('-');}
//  if (x > 9) output(x / 10);
//  putchar(x % 10 + '0');
//  }
/**Maintain your determination.Nobody knows the magnificent landscape
at his destination before the arrival with stumble.**/
/**Last Remote**/
ll dp[199][1990],ar[199];
bool vis[199];
bool dfs(ll current, ll target)
{
    if (target == 0)
        return true;
    else if (target < 0)
        return false;
    else
    {
        if (current < 1)
            return false;
        if (dfs(current - 1, target - ar[current]) == true)//注意01背包的两种状态
        {
            cout << ar[current] << " ";
            return true;
        }
        else
            dfs(current - 1, target);
    }
}
int DETERMINATION()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    ll s, n;
    cin >> s >> n;
    for (int i = 1; i <= n; i++)
        cin >> ar[i];
    if (dfs(n,s) == true);
    else
        cout << "Failed!" << endl;
    return 0;
}

H 01背包模板题

记忆化搜索/递推式皆可,但是数据大了就只能用滚动数组优化的递推

//#include<pch.h>
#include <iostream>
#include <cstdio>
#include <bits/stdc++.h>
#include <queue>
#include <map>
#include <algorithm>
#include <stack>
#include <iomanip>
#include <cstring>
#include <cmath>
#define DETERMINATION main
#pragma GCC optimize(2)
#pragma warning(disable:4996)
#define lldin(a) scanf("%lld", &a)
#define println(a) printf("%lld\n", a)
#define print(a) printf("%lld ", a)
#define reset(a, b) memset(a, b, sizeof(a))
#define debug cout<<"procedures above are available"<<endl;
#define BigInteger __int128
using namespace std;
const int INF = 2e9 + 2;
const double PI = acos(-1);
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int mod = 1e9 + 7;
//template<typename T>
//inline BigInteger nextLong()
//{
//  BigInteger tmp = 0, si = 1;char c;  c = getchar();
//  while (!isdigit(c))
//{if (c == '-')si = -1;c = getchar();}
//  while (isdigit(c))
//  {tmp = tmp * 10 + c - '0';c = getchar();}
//  return si * tmp;    
//}         
//std::ostream& operator<<(std::ostream& os, __int128 T)
//{
//    if (T<0) os<<"-";if (T>=10 ) os<<T/10;if (T<=-10) os<<(-(T/10));
//    return os<<( (int) (T%10) >0 ? (int) (T%10) : -(int) (T%10) ) ;
//}
//void output(BigInteger x)
//{
//  if (x < 0)
//  {x = -x;putchar('-');}
//  if (x > 9) output(x / 10);
//  putchar(x % 10 + '0');
//  }
/**Maintain your determination.Nobody knows the magnificent landscape
at his destination before the arrival with stumble.**/
/**Last Remote**/
ll dp[2300][2300];
struct data2
{
    ll w, v;
}datas[99999];
bool vis[2300][2300];
ll dfs(ll current, ll remaining,ll limit)
{
    ll &tmp = dp[current][remaining];
    if (tmp)
        return tmp;
    else if (current > limit)
        return dp[current][remaining] = 0;
    else
    {
        ll ans1 = dfs(current + 1, remaining, limit);
        ll ans2 = -INF;
        if (remaining >= datas[current].w)
            ans2 = dfs(current + 1, remaining - datas[current].w, limit)+datas[current].v;
        return dp[current][remaining]=max(ans1,ans2);
    }
}
int DETERMINATION()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    ll m, n;
    cin >> m >> n;
    for (int i = 1; i <= n; i++)
        cin >> datas[i].w >> datas[i].v;
    cout << dfs(0, m, n) << endl;
    return 0;
}

I 超级教主

对本题的分析应该从状态转移方程入手。

首先假设状态为吃掉某个能量球之后剩下的能量,于是对于每个能量球而言,就有两种情况:直接吃掉这个能量球及以下的能量球,或者吃完下边某个能量球之后再吃当前这个能量球。

于是显然就有状态转移方程dp[i]=max(dp[i],dp[j]+(sum[i]-sum[j])-100*i)。这个方程的sum[i]和100i,sum[j]都是随着i或j的变化而单调递增的,所以可以把方程后半部分看作(dp[j]-sum[j])+(sum[i]-100*i),i可以由一个循环遍历,而dp[j]和sum[j]就需要用一个单调队列存储一个整体的最大值。

#include<pch.h>
#include <iostream>
#include <cstdio>
#include <bits/stdc++.h>
#include <queue>
#include <map>
#include <algorithm>
#include <stack>
#include <iomanip>
#include <cstring>
#include <cmath>
#define DETERMINATION main
#pragma GCC optimize(2)
#pragma warning(disable:4996)
#define lldin(a) scanf("%d", &a)
#define println(a) printf("%d\n", a)
#define print(a) printf("%lld ", a)
#define reset(a, b) memset(a, b, sizeof(a))
#define debug cout<<"procedures above are available"<<endl;
#define BigInteger __int128
using namespace std;
const int INF = 2e9 + 2;
const double PI = acos(-1);
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int mod = 1e9 + 7;
//template<typename T>
//inline BigInteger nextBigInteger()
//{
//	BigInteger tmp = 0, si = 1;char c;	c = getchar();
//	while (!isdigit(c))
//{if (c == '-')si = -1;c = getchar();}
//	while (isdigit(c))
//	{tmp = tmp * 10 + c - '0';c = getchar();}
//	return si * tmp;	
//}			
//std::ostream& operator<<(std::ostream& os, __int128 T)
//{
//    if (T<0) os<<"-";if (T>=10 ) os<<T/10;if (T<=-10) os<<(-(T/10));
//    return os<<( (int) (T%10) >0 ? (int) (T%10) : -(int) (T%10) ) ;
//}
//void output(BigInteger x)
//{
//	if (x < 0)
//	{x = -x;putchar('-');}
//	if (x > 9) output(x / 10);
//	putchar(x % 10 + '0');
//	}
/**Maintain your determination.Nobody knows the magnificent landscape
at his destination before the arrival with stumble.**/
/**Last Remote**/
int dp[2000020];
int sum[2000020],a[2090020];
int queues[2090020];
int DETERMINATION()
{
	//ios::sync_with_stdio(false);
	//cin.tie(0), cout.tie(0);
	int n,init;
	lldin(n), lldin(init);
	for (int i = 1; i <= n; i++)
		lldin(a[i]);
	for (int i = 1; i <= n; i++)
		sum[i] = sum[i - 1] + a[i];
	int pt1 = 1,pt2 = 1;
	dp[0] = init;//初始化
	for (int i = 1; i <= n; i++)
	{
		while (pt2 > pt1&&(dp[queues[pt1+1]] - i*100) < 0)//如果说这个点压根跳不上去
			pt1++;
		while (pt2 > pt1&&(dp[queues[pt2]]-queues[queues[pt2]]) < (dp[i-1]-sum[i-1]))
			pt2--;
		queues[++pt2] = i - 1;
		dp[i] = max(dp[i], (dp[queues[pt1+1]] - sum[queues[pt1+1]]) + sum[i] - 100 * i);
		//println(dp[i]);
		
	}
	println(dp[n]);
	return 0;
}

简单背包问题||

这是01背包模板题,记忆化搜索与递推皆可

import java.io.*;
import java.util.*;
import java.math.*;
import java.text.*;
public class Main
{
    static int dp[][]=new int[34][20090];
    public static int dfs(int current,int v,int limit,int inventory[])
    {
        if(dp[current][v]>0)
            return dp[current][v];
        else if(current>limit)
            return dp[current][v]=0;
        else
        {
            int ans1=0,ans2=0;
            if(v>=inventory[current])
                ans1=dfs(current+1, v-inventory[current], limit, inventory)+inventory[current];
            ans2=dfs(current+1,v,limit,inventory);
            return dp[current][v]=Math.max(ans1,ans2);
        }
    }
    public static void main(String args[])throws IOException
    {
        StreamTokenizer st=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
        PrintWriter pw=new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
        st.nextToken();int v=(int)st.nval;
        st.nextToken();int n=(int)st.nval;
        int ar[]=new int[n+122];
        for(int i=1;i<=n;i++)
        {
            st.nextToken();ar[i]=(int)st.nval;
        }
        pw.println(v-dfs(1, v,n, ar));
        pw.flush();
        pw.close();
    }
}

货币系统问题

这类似于走楼梯问题的解法。对于每个面值来说,它可以继承(当前面值-某种货币)面值的凑法数,如此处理到N就是答案

import java.io.*;
import java.util.*;
import java.math.*;
import java.text.*;
public class Main
{
    static int dp[]=new int[1599];
    static int arr[]=new int[1599];
    public static void main(String args[])throws IOException
    {
        StreamTokenizer st=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
        PrintWriter pw=new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
        int v,n;
        st.nextToken();n=(int)st.nval;
        st.nextToken();v=(int)st.nval;
        for(int i=1;i<=n;i++)
        {
            st.nextToken();arr[i]=(int)st.nval;
        }
        dp[0]=1;
        for(int i=1;i<=n;i++)
            for(int j=arr[i];j<=v;j++)
            {
                dp[j]+=dp[j-arr[i]];
            }
        pw.println(dp[v]);
        pw.flush();
        pw.close();
    }
}

货币面值

由于每种货币只能用一次,所以可以看做一个01背包,数组下标对应所求金额,值的正负决定是否有方案。如果容量为i的时候对应的值大于0(初始化为负值),那么就是有凑数方案的,反之没有,找出最小值即可。

数字分组I

这可以看做一个01背包。其中最大容量是所有数总和的一半,找出这样一个最大值之后与总和作差即可。

数字分组II

此题并没有什么很明显的规律,但是数据范围很小,所以直接用状态压缩枚举即可。1到2^n-1的二进制表达式就可以代表分组方式,记录合法差值的最大值即可。

//#include<pch.h>
#include <iostream>
#include <cstdio>
#include <bits/stdc++.h>
#include <queue>
#include <map>
#include <algorithm>
#include <stack>
#include <iomanip>
#include <cstring>
#include <cmath>
#define DETERMINATION main
#pragma GCC optimize(2)
#pragma warning(disable:4996)
#define lldin(a) scanf("%lld", &a)
#define println(a) printf("%lld\n", a)
#define print(a) printf("%lld ", a)
#define reset(a, b) memset(a, b, sizeof(a))
#define debug cout<<"procedures above are available"<<endl;
#define BigInteger __int128
using namespace std;
const int INF = 2e9 + 2;
const double PI = acos(-1);
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int mod = 1e9 + 7;
//template<typename T>
//inline BigInteger nextBigInteger()
//{
//  BigInteger tmp = 0, si = 1;char c;  c = getchar();
//  while (!isdigit(c))
//{if (c == '-')si = -1;c = getchar();}
//  while (isdigit(c))
//  {tmp = tmp * 10 + c - '0';c = getchar();}
//  return si * tmp;    
//}         
//std::ostream& operator<<(std::ostream& os, __int128 T)
//{
//    if (T<0) os<<"-";if (T>=10 ) os<<T/10;if (T<=-10) os<<(-(T/10));
//    return os<<( (int) (T%10) >0 ? (int) (T%10) : -(int) (T%10) ) ;
//}
//void output(BigInteger x)
//{
//  if (x < 0)
//  {x = -x;putchar('-');}
//  if (x > 9) output(x / 10);
//  putchar(x % 10 + '0');
//  }
/**Maintain your determination.Nobody knows the magnificent landscape
at his destination before the arrival with stumble.**/
/**Last Remote**/
ll inventories[50];
int DETERMINATION()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    ll n;
    cin >> n;
    ll mx = 0, sum = 0;
    for (int i = 1; i <= n; i++)
    {
        cin >> inventories[i];
        sum += inventories[i];
        mx = max(mx, inventories[i]);
    }
    ll ans = 0;
    for (int i = 1; i <(1<<n); i++)
    {
        //cout << bitset<10>(i) << endl;
        ll tmpsum = 0, tmpans = 0;
        for (int j = 1; j <= n; j++)
        {
            if (((i >> j) & 1) > 0)
                tmpsum += inventories[j];
        }
        tmpans = abs(tmpsum-abs(sum - tmpsum));
        if (tmpans <= mx)
            ans = max(tmpans, ans);
    }
    cout << ans << endl;
    return 0;
}

完全背包问题

这是完全背包的模板题,递推即可。不建议使用记忆化搜索,因为很可能内存超限。

收益

这是一个比较奇特的完全背包问题。因为它在模板的基础上多添加了一次循环,也就是题目中所谓天数的循环。在每一天内,可以看出目前已有的资金与债券间构成了一个完全背包的关系,对每一天的收益进行求解,并把收益加到总资金里,如此进行操作到天数为n即可

值得一说的是,由于题目所说这些价格和本金都是1000的倍数,那么就可以把这些数都除以1000以简化对背包空间的枚举。

//#include<pch.h>
#include <iostream>
#include <cstdio>
#include <bits/stdc++.h>
#include <queue>
#include <map>
#include <algorithm>
#include <stack>
#include <iomanip>
#include <cstring>
#include <cmath>
#define DETERMINATION main
#pragma GCC optimize(2)
#pragma warning(disable:4996)
#define lldin(a) scanf("%lld", &a)
#define println(a) printf("%lld\n", a)
#define print(a) printf("%lld ", a)
#define reset(a, b) memset(a, b, sizeof(a))
#define debug cout<<"procedures above are available"<<endl;
#define BigInteger __int128
using namespace std;
const int INF = 2e9 + 2;
const double PI = acos(-1);
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int mod = 1e9 + 7;
//template<typename T>
//inline BigInteger nextBigInteger()
//{
//  BigInteger tmp = 0, si = 1;char c;  c = getchar();
//  while (!isdigit(c))
//{if (c == '-')si = -1;c = getchar();}
//  while (isdigit(c))
//  {tmp = tmp * 10 + c - '0';c = getchar();}
//  return si * tmp;    
//}         
//std::ostream& operator<<(std::ostream& os, __int128 T)
//{
//    if (T<0) os<<"-";if (T>=10 ) os<<T/10;if (T<=-10) os<<(-(T/10));
//    return os<<( (int) (T%10) >0 ? (int) (T%10) : -(int) (T%10) ) ;
//}
//void output(BigInteger x)
//{
//  if (x < 0)
//  {x = -x;putchar('-');}
//  if (x > 9) output(x / 10);
//  putchar(x % 10 + '0');
//  }
/**Maintain your determination.Nobody knows the magnificent landscape
at his destination before the arrival with stumble.**/
/**Last Remote**/
ll dp[250000];
pair<ll, ll>stocks[50000];
int DETERMINATION()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    ll t;
    cin >> t;
    while (t--)
    {
        ll initfund, n;
        cin >> initfund >> n;
        ll d;
        cin >> d;
        for (int i = 1; i <= d; i++)
        {
            cin >> stocks[i].first >> stocks[i].second;
            stocks[i].first/= 1000;
        }
        ll capital;
        for (int i = 1; i <= n; i++)
        {
            capital = initfund / 1000;//现有资本
            reset(dp, 0);//清空这个滚动数组
            for (int j = 1; j <= d; j++)
                for (int k = stocks[j].first; k <= capital; k++)
                    dp[k] = max(dp[k - stocks[j].first] + stocks[j].second, dp[k]);
            initfund += dp[capital];//本金+收益
        }
        cout << initfund << endl;
    }
    return 0;
}

多重背包

这是多重背包的模板题,也是综合了三种背包问题的集大成者。这个模板的主要内容可以由如下流程表述

  1. 第一步是构建最外层的物品序号循环
  2. 第二步是判断当前物品是否超出或等于背包的容量,如果是,就进行完全背包的操作(能装多少装多少)
  3. 第三步是进行状态压缩优化的二进制枚举的多重背包的操作,这样的优化有一次装载多个物品的效果,可以优化时间
  4. 第四步是检查是否还漏下一些物品没有装,如果是,就进行01背包,直接把剩余物品乘以余下的常数当做整体放入即可。

说来说去这个用滚动数组优化的动态规划数组只有一维,而针对于某一个物品就进行了上述如此多的操作,它是怎么保证答案正确性的呢?

滚动数组的优化是由于某个状态转移方程的一个维度在任意状态时只与相邻状态有关,故而省略这一个维度所存储的大部分数据所做的优化。

如何理解呢?比如说01背包问题的状态转移方程是dp[i][j]=max(dp[i-1][j-w[i]]+v[i],dp[i-1][j]),也就是说每个i只和i-1有关,和i-2什么的统统没有关系(这也是动态规划状态上的无后效性决定的),而且你还不想保存过去数据的话,就可以直接用0和1代替第一维,即只有当前物品和前一个物品这两个状态,在这两个状态间迭代就可以得到最终答案。

实际上,也完全可以省掉这一个维度,直接用一维数组进行计算也是可以的,但是这个就需要确定好滚动方向,以免造成数据未更新或者一些不必要的覆盖。

比如滚动数组优化后的01背包状态转移方程dp[j]=max(dp[j],dp[j-w[i]]+v[i]),如果你正向枚举j的话,就会出现一个尴尬的事情:当你枚举到某个位置的时候,你会发现dp[j-w[i]]保存的是dp[i][j-w[i]]而不是dp[i-1][j-w[i]],因为前者你已经在正向循环中计算过了,所以原本的状态数据被覆盖掉,就会导致错误的答案(这是完全背包的解法而不是01背包的解法)。所以就需要采取逆向循环枚举。

比如一组数据:70 3(容量  物品数量)

71 100,69 1,1 2,(体积和价值)

  1. 当你分析第一个物品时,你会发现这个无法装入背包,故动态规划数组内所有值仍然是0
  2. 当你分析第二个物品时,这个物品可以装入背包,逆向循环后只有dp[69]和dp[70]的值都是1
  3. 当你分析第三个物品时,这个物品可以装入背包,逆向循环时,dp[70] 保存的实际上是dp[2][70]的值,同样dp[69]也是dp[2][69]的值,而dp[3][70]会由dp[2][69]和dp[2][70]转移而来,之前的数据还未覆盖,可以用来计算。答案为3
#include<pch.h>
#include <iostream>
#include <cstdio>
#include <bits/stdc++.h>
#include <queue>
#include <map>
#include <algorithm>
#include <stack>
#include <iomanip>
#include <cstring>
#include <cmath>
#define DETERMINATION main
#pragma GCC optimize(2)
#pragma warning(disable:4996)
#define lldin(a) scanf("%lld", &a)
#define println(a) printf("%lld\n", a)
#define print(a) printf("%lld ", a)
#define reset(a, b) memset(a, b, sizeof(a))
#define debug cout<<"procedures above are available"<<endl;
#define BigInteger __int128
using namespace std;
const int INF = 2e9 + 2;
const double PI = acos(-1);
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int mod = 1e9 + 7;
//template<typename T>
//inline BigInteger nextBigInteger()
//{
//	BigInteger tmp = 0, si = 1;char c;	c = getchar();
//	while (!isdigit(c))
//{if (c == '-')si = -1;c = getchar();}
//	while (isdigit(c))
//	{tmp = tmp * 10 + c - '0';c = getchar();}
//	return si * tmp;	
//}			
//std::ostream& operator<<(std::ostream& os, __int128 T)
//{
//    if (T<0) os<<"-";if (T>=10 ) os<<T/10;if (T<=-10) os<<(-(T/10));
//    return os<<( (int) (T%10) >0 ? (int) (T%10) : -(int) (T%10) ) ;
//}
//void output(BigInteger x)
//{
//	if (x < 0)
//	{x = -x;putchar('-');}
//	if (x > 9) output(x / 10);
//	putchar(x % 10 + '0');
//	}
/**Maintain your determination.Nobody knows the magnificent landscape
at his destination before the arrival with stumble.**/
/**Last Remote**/
struct inventory
{
	ll amount, volume, value;
}inventories[599997];
ll dp[599997];
int DETERMINATION()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	int n, v;
	cin >> v>> n;
	for (int i = 1; i <= n; i++)
		cin >> inventories[i].volume >> inventories[i].value >> inventories[i].amount;
	for (int i = 1; i <= n; i++)
	{
		if (inventories[i].amount*inventories[i].volume >= v)
		{
			for (int j = inventories[i].volume; j <= v; j++)
				dp[j] = max(dp[j], dp[j - inventories[i].volume] + inventories[i].value);
		}
		else
		{
			ll tmpcnt = inventories[i].amount;
			for (int k = 1; k <= tmpcnt; k <<= 1)
			{
				for (int j = v; j >= inventories[i].volume*k; j--)
					dp[j] = max(dp[j], dp[j - inventories[i].volume*k] + inventories[i].value*k);
				tmpcnt -= k;
			}
			if (tmpcnt)
			{
				for (int j = v; j >= inventories[i].volume * tmpcnt; j--)
					dp[j] = max(dp[j], dp[j - inventories[i].volume* tmpcnt] + inventories[i].value*tmpcnt);
			}
		}
	}
	cout << dp[v] << endl;
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
安装完PI服务端,重新启动计算机后,PI系统就开始运行了,这时PI的默认数据库只有3个,大小为安装时配置的1024M,此时还需再增加几个数据库,以保证数据长时间存放,增加方法如下,点击“开始”—“运行”,输入“CMD”,然后转到PI安装目录,例如:“c:\pi\adm”。这时,运行创建数据库文件命令,命令格式如下: ●创建数据库文件 piarcreate -d path maxpoints maxsize(Mb) piarcreate path size(Mb) eg: piarcreate .exe D:\PIPC\DAT\ piarch.004 1024 ●关联数据库文件 piartool.exe -ar path eg: piartool.exe –ar D:\PIPC\DAT\ piarch.004 3.配置接口机和服务器之间的通讯。 有些网络中,接口机和服务器之间的通讯需要在服务器端开通和接口机的认证,同增加数据库的方法一样,进入“c:\pi\adm”,运行“piconfig”命令,进入PI系统命令格式。运行如下: C:\PI\adm>piconfig * (Ls - ) PIconfig> table pitrust //选择表 * (Ls - PITRUST) PIconfig> @mode creat //进入创建模式 * (Cr - PITRUST) PIconfig> @istr trust,ipaddr,netmask,piuser //这里trust可以自己取个名字,IPADDR就是接口机的IP地址,netmask是255.255.255.255,piuser 用piadmin * (Cr - PITRUST) PIconfig> client2, 192.168.28.227,255.255.255.255,piadmin //例子 * (Cr - PITRUST) PIconfig> @ends * (Cr - PITRUST) PIconfig> @mode list //浏览模式 * (Ls - PITRUST) PIconfig> @ostr * * (Ls - PITRUST) PIconfig> @sele trust = * //选择所有TRUST名 * (Ls - PITRUST) PIconfig> @ends //结束后系统会列举出所有的配置 二.PI OPC接口机的安装及配置 PI OPC接口机端的安装源程序由3部分组成,在PIOPC目录下面,有2个文件夹“PIAPI”和“NTI”,先安装PIAPI,安装时配置如下:
node.js Windowv 上安装Node.js Windows 安装包(.msi) : 32 位安装包下载地址 : http://nodejs.org/dist/v0.10.26/node-v0.10.26-x86.msi 64 位安装包下载地址 : http://nodejs.org/dist/v0.10.26/x64/node-v0.10.26-x64.msi 安装步骤: 步骤 1 : 双击下载后的安装包 node-v0.10.26-x86.msi,如下所示: install-node-msi-version-on-windows-step1 步骤 2 : 点击以上的Run(运行),将出现如下界面: install-node-msi-version-on-windows-step2 步骤 3 : 勾选接受协议选项,点击 next(下一步) 按钮 : install-node-msi-version-on-windows-step3 步骤 4 : Node.js默认安装目录为 "C:\Program Files\nodejs\" , 你可以修改目录,并点击 next(下一步): install-node-msi-ve rsion-on-windows-step4 步骤 5 : 点击树形图标来选择你需要的安装模式 , 然后点击下一步 next(下一步) install-node-msi-version-on-windows-step5 步骤 6 :点击 Install(安装) 开始安装Node.js。你也可以点击 Back(返回)来修改先前的配置。 然后并点击 next(下一步): install-node-msi-version-on-windows-step6 安装过程: install-node-msi-version-on-windows-step7 点击 Finish(完成)按钮退出安装向导。 install-node-msi-version-on-windows-step8 检测PATH环境变量是否配置了Node.js,点击开始=》运行=》输入"cmd" => 输入命令"path",输出如下结果: PATH=C:\oraclexe\app\oracle\product\10.2.0\server\bin;C:\Windows\system32; C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\; c:\python32\python;C:\MinGW\bin;C:\Program Files\GTK2-Runtime\lib; C:\Program Files\MySQL\MySQL Server 5.5\bin;C:\Program Files\nodejs\; C:\Users\rg\AppData\Roaming\npm 我们可以看到环境变量中已经包含了C:\Program Files\nodejs\ 检查Node.js版本 node-version-test Windows 二进制文件 (.exe)安装 : 32 位安装包下载地址 : http://nodejs.org/dist/v0.10.26/node.exe 64 位安装包下载地址 : http://nodejs.org/dist/v0.10.26/x64/node.exe 安装步骤 步骤 1 : 双击下载的安装包 Node.exe ,将出现如下界面 : install-node-exe-on-windows-step1 点击 Run(运行)按钮将出现命令行窗口: install-node-exe-on-windows-step21 版本测试 进入 node.exe 所在的目录,如下所示: node-version 如果你获得以上输出结果,说明你已经成功安装了Node.js。 Linux上安装 Node.js Ubuntu 源码安装 以下部分我们将介绍在Ubuntu Linux下安装 Node.js 。 其他的Linux系统,如Centos等类似如下安装步骤。 在 Github 上获取 Node.js 源码: install-node-msi-version-on-linux-step1 install-node-msi-version-on-linux-step2 在完成下载后,将源码包名改为 'node'。 install-node-msi-version-on-linux-step3 修改目录权限: install-node-msi-version-on-linux-step4 使用 './configure' 创建编译文件。 install-node-msi-version-on-linux-step5 编译: make。 install-node-msi-version-on-linux-step6 完成安装: make install。 install-node-msi-version-on-linux-step7 最后我们输入'node --version' 命令来查看Node.js是否安装成功。 install-node-msi-version-on-linux-step8 Ubuntu apt-get命令安装 命令格式如下: sudo apt-get install nodejs sudo apt-get install npm centOS下安装nodejs 1、下载源码,你需要在http://nodejs.org/下载最新的Nodejs版本,本文以v0.10.24为例: cd /usr/local/src/ wget http://nodejs.org/dist/v0.10.24/node-v0.10.24.tar.gz 2、解压源码 tar zxvf node-v0.10.24.tar.gz 3、 编译安装 cd node-v0.10.24 ./configure --prefix=/usr/local/node/0.10.24 make make install 4、 配置NODE_HOME,进入profile编辑环境变量 vim /etc/profile 设置nodejs环境变量,在export PATH USER LOGNAME MAIL HOSTNAME HISTSIZE HISTCONTROL 一行的上面添加如下内容: #set for nodejs export NODE_HOME=/usr/local/node/0.10.24 export PATH=$NODE_HOME/bin:$PATH :wq保存并退出,编译/etc/profile 使配置生效 source /etc/profile 验证是否安装配置成功 node -v 输出 v0.10.24 表示配置成功 npm模块安装路径 /usr/local/node/0.10.24/lib/node_modules/ 注:Nodejs 官网提供了编译好的Linux二进制包,你也可以下载下来直接应用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值