2016 Multi-University Training Contest 5

本文解析了三道ACM竞赛题目:序列分割、两序列相同子序列数量计算及四元组计数问题,提供了详细算法思路与代码实现。

1003

http://acm.hdu.edu.cn/showproblem.php?pid=5783

Divide the Sequence

Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 2232    Accepted Submission(s): 628


Problem Description
Alice has a sequence A, She wants to split A into as much as possible continuous subsequences, satisfying that for each subsequence, every its prefix sum is not small than 0.
 

Input
The input consists of multiple test cases.
Each test case begin with an integer n in a single line.
The next line contains n integers A1,A2An.
1n1e6
10000A[i]10000
You can assume that there is at least one solution.
 

Output
For each test case, output an integer indicates the maximum number of sequence division.
 

Sample Input
6 1 2 3 4 5 6 4 1 2 -3 0 5 0 0 0 0 0
 

Sample Output
6 2 5
 

题目意思是把一个序列分成尽量多的序列,使得每个序列的前缀和大于等于0。(另外,题目数据保证每个[1, i]的前缀和大于等于0,并且一定有解)

因为忽略了括号里的条件,我觉得这是个dp问题,简单题,然后就tle了,顺手记一下dp的程序:

dp[i]表示[1, i]最多能形成多少个段。那么转移方程如下:

dp[i] = Max(dp[i], dp[j - 1] + (sum[i] - sum[j - 1] >= 0));

<span style="font-size:18px;">//#include<bits/stdc++.h>
#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<iterator>
#include<math.h>
#include<stdlib.h>
#include<time.h>
#include<map>
#include<set>
using namespace std;
//#define ONLINE_JUDGE
#define eps 1e-8
#define inf 0x3f3f3f3f
#define INF 0x7fffffff
#define INFL 0x3f3f3f3f3f3f3f3fLL
#define enter putchar(10)
#define rep(i,a,b) for(int i = (a); i < (b); ++i)
#define repe(i,a,b) for(int i = (a); i <= (b); ++i)
#define mem(a,b) (memset((a),b,sizeof(a)))
#define sf(a) scanf("%d",&a)
#define sfI(a) scanf("%I64d",&a)
#define sfd(a,b) scanf("%d%d",&a,&b)
#define sft(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define sfs(a) scanf("%s",a)
#define pf(a) printf("%d\n",a)
#define pfd(a,b) printf("%d %d\n",a,b)
#define pfP(a) printf("%d %d\n",a.fi,a.se)
#define pfs(a) printf("%s\n",a)
#define pfI(a) printf("%I64d\n",a)
#define ds(a) int a; sf(a)
#define PR(a,b) pair<a,b>
#define fi first
#define se second
#define LL long long
#define DB double
const double PI = acos(-1.0);
const double E = exp(1.0);
template<class T> T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template<class T> T lcm(T a, T b) { return a / gcd(a, b) * b; }
template<class T> inline T Min(T a, T b) { return a < b ? a : b; }
template<class T> inline T Max(T a, T b) { return a > b ? a : b; }
int n, m;
const int N = (1e+6) + 10;
int sum[N];
int dp[N];

void check() {
    repe(i, 1, n) {
        printf("%d ", dp[i]);
    }
    enter; enter;
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
//    freopen("Out.txt", "w", stdout);
#endif
    while(~sf(n)) {
        mem(dp, 0);
        sum[0] = 0;
        repe(i, 1, n) {
            sf(sum[i]);
            sum[i] += sum[i - 1];
        }
        repe(i, 1, n) {
            repe(j, i, n) {
                if(sum[j] - sum[i - 1] >= 0) dp[j] = Max(dp[j], dp[i - 1] + 1);
            }
        }
        pf(dp[n]);
    }
    return 0;
}</span>

后来发现是tle,我想,这个dp好像没法变成一维(因为数组没法开dp[1e + 6][1e + 6]),那可不可能把二维数组用滚动数组的方式优化成一维,但是,好想也没办法(既然一维能表示状态而且能递推,为什么要弄到二维去?)

后来我们发现我们忽略了一个条件,数据中的序列的每一项的前缀和保证大于等于0,既然这样我们就可以采用贪心的方法,sum[1, i] 保证大于等于0,加入sum[j, i]大于等于0,那么[i, j]就可以被分成一段,所以从后往前扫一遍就行了。。。

<span style="font-size:18px;">//#include<bits/stdc++.h>
#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<iterator>
#include<math.h>
#include<stdlib.h>
#include<time.h>
#include<map>
#include<set>
using namespace std;
//#define ONLINE_JUDGE
#define eps 1e-8
#define inf 0x3f3f3f3f
#define INF 0x7fffffff
#define INFL 0x3f3f3f3f3f3f3f3fLL
#define enter putchar(10)
#define rep(i,a,b) for(int i = (a); i < (b); ++i)
#define repe(i,a,b) for(int i = (a); i <= (b); ++i)
#define mem(a,b) (memset((a),b,sizeof(a)))
#define sf(a) scanf("%d",&a)
#define sfI(a) scanf("%I64d",&a)
#define sfd(a,b) scanf("%d%d",&a,&b)
#define sft(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define sfs(a) scanf("%s",a)
#define pf(a) printf("%d\n",a)
#define pfd(a,b) printf("%d %d\n",a,b)
#define pfP(a) printf("%d %d\n",a.fi,a.se)
#define pfs(a) printf("%s\n",a)
#define pfI(a) printf("%I64d\n",a)
#define ds(a) int a; sf(a)
#define PR(a,b) pair<a,b>
#define fi first
#define se second
#define LL long long
#define DB double
const double PI = acos(-1.0);
const double E = exp(1.0);
template<class T> T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template<class T> T lcm(T a, T b) { return a / gcd(a, b) * b; }
template<class T> inline T Min(T a, T b) { return a < b ? a : b; }
template<class T> inline T Max(T a, T b) { return a > b ? a : b; }
int n, m;
#define N 1000010
int a[N];
LL sum;

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
//    freopen("Out.txt", "w", stdout);
#endif
    while(~sf(n)) {
        rep(i, 0, n) sf(a[i]);
        sum = 0;
        int ans = 0;
        for(int i = n - 1; i >= 0; i--) {
            sum += a[i];
            if(sum >= 0) {
                ans++;
                sum = 0;
            }
        }
        pf(ans);
    }
    return 0;
}</span>

well, 下一题。。

1011

http://acm.hdu.edu.cn/showproblem.php?pid=5791

Two

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1500    Accepted Submission(s): 414


Problem Description
Alice gets two sequences A and B. A easy problem comes. How many pair of sequence A' and sequence B' are same. For example, {1,2} and {1,2} are same. {1,2,4} and {1,4,2} are not same. A' is a subsequence of A. B' is a subsequence of B. The subsequnce can be not continuous. For example, {1,1,2} has 7 subsequences {1},{1},{2},{1,1},{1,2},{1,2},{1,1,2}. The answer can be very large. Output the answer mod 1000000007.
 

Input
The input contains multiple test cases.

For each test case, the first line cantains two integers N,M(1N,M1000). The next line contains N integers. The next line followed M integers. All integers are between 1 and 1000.
 

Output
For each test case, output the answer mod 1000000007.
 

Sample Input
3 2 1 2 3 2 1 3 2 1 2 3 1 2
 

Sample Output
2 3
 题目意思是求两个序列最多有多少个顺序相同的子序列。。一道大水题。
这题不是我写的,待会上传代码


无疑是dp嘛,状态表示也很好想不过转移方程得想一下。
用dp[i][j]表示a[1 , i] 能和 b[1, j] 能形成的公共子序列个数,无疑dp[i][j] = 0 (i == 0 || j == 0)
初状态就有了,现在来考虑转移方程。
先考虑a[i] != b[j] 的情况:
    dp[i][j] = dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1];(容斥原理嘛,a[i] 和 b[j - 1]能构成的子序列个数 + a[i - 1] 和 b[j] 能构成的子序列个数 - a[i - 1] 和 b[j - 1] 能构成的子序列个数(因为在算[i, j - 1] 和 [i - 1, j]的时候重复算了一次))
那么如果a[i] == b[j] 呢?
   dp[i][j] 在a[i] != b[j] 的基础上 + dp[i - 1][j - 1] + 1;因为a[i] == b[j], a[1 , i - 1] 和 b[1, j - 1] 能形成的任何一个子序列再加上a[i](同时也是b[j])又能形成新的一个子序列(并且和原来不同,因为多了a[i]),所以能形成的新的个数自然是dp[i - 1][j - 1]个了, 并且 a[i] 自己也能形成一个仅有a[i]的序列, 所以再加上1,这样就得到了 dp[i][j] .
所以状态转移方程如下:
dp[i][j] = dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1] + (a[i] == b[j] ? dp[i - 1][j - 1] + 1 : 0);

这道题也很好解了:
/*************************************************************************
    > File Name: 1011.cpp
    > Author: Triose
    > Mail: Triose@163.com 
    > Created Time: 2016年08月03日 星期三 13时48分21秒
 ************************************************************************/

//#include<bits/stdc++.h>
#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<iterator>
#include<math.h>
#include<stdlib.h>
#include<time.h>
#include<map>
#include<set>
using namespace std;
//#define ONLINE_JUDGE
#define eps 1e-8
#define inf 0x3f3f3f3f
#define INF 0x7fffffff
#define INFL 0x3f3f3f3f3f3f3f3fLL
#define enter putchar(10)
#define rep(i,a,b) for(int i = (a); i < (b); ++i)
#define repe(i,a,b) for(int i = (a); i <= (b); ++i)
#define mem(a,b) (memset((a),b,sizeof(a)))
#define sf(a) scanf("%d",&a)
#define sfI(a) scanf("%I64d",&a)
#define sfd(a,b) scanf("%d%d",&a,&b)
#define sft(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define sfs(a) scanf("%s",a)
#define pf(a) printf("%d\n",a)
#define pfd(a,b) printf("%d %d\n",a,b)
#define pfP(a) printf("%d %d\n",a.fi,a.se)
#define pfs(a) printf("%s\n",a)
#define pfI(a) printf("%I64d\n",a)
#define ds(a) int a; sf(a)
#define PR(a,b) pair<a,b>
#define fi first
#define se second
#define LL long long
#define DB double
const double PI = acos(-1.0);
const double E = exp(1.0);
template<class T> T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template<class T> T lcm(T a, T b) { return a / gcd(a, b) * b; }
template<class T> inline T Min(T a, T b) { return a < b ? a : b; }
template<class T> inline T Max(T a, T b) { return a > b ? a : b; }
int n, m;
const int MOD = (1e+9) + 7;
#define N 1010
int a[N], b[N]; 
LL dp[N][N];

void Init() {
    mem(dp, 0);
    repe(i, 1, n) sf(a[i]);
    repe(j, 1, m) sf(b[j]);
}

void solve() {
    repe(i, 1, n) {
	repe(j, 1, m) {
	    dp[i][j] = (dp[i - 1][j] + dp[i][j - 1] - dp[i- 1][j - 1] + MOD) % MOD;
	    if(a[i] == b[j]) {
		dp[i][j] = (dp[i][j] + dp[i - 1][j - 1] + 1) % MOD;
	    }
	}
    }
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
//  freopen("Out.txt", "w", stdout);
#endif
    while(~sfd(n, m)) {
	Init();
	solve();
	pfI(dp[n][m]);
    }
    return 0;
}


1012

http://acm.hdu.edu.cn/showproblem.php?pid=5792

World is Exploding

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 938    Accepted Submission(s): 340


Problem Description
Given a sequence A with length n,count how many quadruple (a,b,c,d) satisfies: abcd,1a<bn,1c<dn,Aa<Ab,Ac>Ad.
 

Input
The input consists of multiple test cases.
Each test case begin with an integer n in a single line.

The next line contains n integers A1,A2An.
1n50000
0Ai1e9
 

Output
For each test case,output a line contains an integer.
 

Sample Input
4 2 4 1 3 4 1 2 3 4
 

Sample Output
1 0
 
比赛的时候给了一种O(n ^ 2) 的解法(预处理 + 容斥原理)果不其然超时,超时代码就不贴了,就是统计第 i 个位置比比它大的并且在它后面的数的个数,比它大的在它前面的个数,同理统计比它小的在后面和前面的个数, 然后二重循环算一算加一加减一减就好了,超时!
再去做做再来说解法。。。


【电动车优化调度】基于模型预测控制(MPC)的凸优化算法的电动车优化调度(Matlab代码实现)内容概要:本文介绍了基于模型预测控制(MPC)的凸优化算法在电动车优化调度中的应用,并提供了Matlab代码实现。该方法结合了MPC的滚动优化特性与凸优化的高效求解能力,用于解决电动车充电调度问题,提升电网运行效率与可再生能源消纳能力。文中还提及多个相关研究方向和技术支撑,包括智能优化算法、机器学习、电力系统管理等,展示了其在多领域交叉应用的潜力。配套资源可通过提供的网盘链接获取,涵盖YALMIP工具包及其他完整仿真资源。; 适合人群:具备一定电力系统、优化理论及Matlab编程基础的科研人员和研究生,尤其适合从事电动汽车调度、智能电网优化等相关课题的研究者。; 使用场景及目标:①实现电动车集群在分时电价或电网需求响应机制下的有序充电调度;②结合可再生能源出力与负荷预测,利用MPC进行多时段滚动优化,降低电网峰谷差,提高能源利用效率;③为学术论文复现、课题研究及工程仿真提供可靠的技术路线与代码支持。; 阅读建议:建议读者结合文档中提到的智能优化算法与电力系统背景知识进行系统学习,优先掌握MPC基本原理与凸优化建模方法,并下载配套资源调试代码,以加深对电动车调度模型构建与求解过程的理解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值