2019_C2

A C2-妙妙趣和值

题面

定义一个长度为kk的数组a1,a2,,aka_{1},a_{2},⋯,a_{k}的妙妙趣值是min1i<jkaiaj\min\limits_{1≤i<j≤k}|ai−aj|
那么请问对于一个长度为nn序列,所有长度为kk子序列的妙妙趣值和为多少。

某个序列的子序列是从最初序列通过去除某些元素但不破坏余下元素的相对位置(在前或在后)而形成的新序列。

答案为100000007取模

输入

第一行两个数n,kn,k,表示序列的长度,子序列的长度。(2kn1000)(2≤k≤n≤1000)

接下来一行,nn个整数a1,a2,,an,(0ai105)a_{1},a_{2},⋯,a_{n},(0≤a_{i}≤10^{5})

输出

一行一个数,表示妙妙趣和值

输入样例
4 3
1 7 3 5
输出样例
8
样例解释
长度为3的子序列有 [1,7,3], [1,3,5], [7,3,5], [1,7,5],每一个妙妙趣值都是2
思路

子序列:某个序列的子序列是从最初序列通过去除某些元素但不破坏余下元素的相对位置(在前或在后)而形成的新序列。即不要求连续,只要求相对位置保持不变。

难题

首先考虑一点,妙妙趣值与子序列的顺序没有关系。

进一步考虑,我们更改原序列的顺序后,对妙妙趣值和没有影响。
所以我们先对原序列进行排序。

然后考虑一个问题,在一个非下降序列中,长度为kxaiajk,x≤|a_{i}-a_{j}|(注意不是妙妙趣值是xx)的子序列有多少个。

这个问题是dp可做的。

dp[i][j]dp[i][j][1,i][1,i]区间里的,长度为jjxaiajx≤|a_{i}-a_{j}|的序列个数。

那么的dp[i][j]=dp[i1][j]+dp[li][j1]dp[i][j] = dp[i-1][j] + dp[l_{i}][j-1],其中lil_{i}是满足ali+xa[i]a_{l_{i}}+x≤a_[i]的最大值。

如何统计答案?
注意dp(x)dp(x)xminaiajx≤min|a_{i}-a_{j}|的子序列个数。
那么minaiaj=xmin|a_{i}-a_{j}|=x的子序列个数就是(dp(x)dp(x+1))(dp(x)-dp(x+1))
这里dp(x)dp(x)指的是枚举xxdp[n][k]dp[n][k]的值
答案就要加上x(dp(x)dp(x+1))x*(dp(x)-dp(x+1))

更好的方式是,我们只需要枚举x,把dp[n][k]加到答案里即可。
为什么这样正确?
注意dp是子序列个数。
一个子序列如果妙妙趣值为y,那么在枚举x为[1,𝑦]的时候这个子序列都会被统计一次。相当于贡献了y。
这个转化就相对于计算i=1naii\sum_{i=1}^{n}a_{i}*i,只需要从后往前算一下前(后)缀和,然后再

那我们枚举x的上界是多少呢?
每个值最大是10510^{5},如果枚举到10510^{5},复杂度高达105nk10^{5}*n*k
事实上我们只需要枚举到max(a)min(a)/k1max(a)-min(a)/k-1即可,思考一下为什么
复杂度为max(a)min(a)/(k1)nkmax(a)-min(a)/(k-1)*n*kkk可以认为被越掉,计为nmax(a)n*max(a)

代码
#include <iostream>
#include <algorithm>
using namespace std;
typedef long double ld;
typedef long long ll;
const int mod = 100000007;
const int ms = 1005;
int n, k;
int a[ms], dp[ms][ms];
int solve(int x){
	dp[0][0] = 1;
	int li = 0;
	for (int i = 1; i <= n; ++i)
	{
		while (a[i] - a[li + 1] >= x) li++;
		dp[i][0] = dp[i - 1][0];
		for (int j = 1; j <= k && j <= i; ++j)
		{
			dp[i][j] = dp[i - 1][j] + dp[li][j - 1];
			dp[i][j] %= mod;
		}
	}
	return dp[n][k];
}
int main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(nullptr);
	cin >> n >> k;
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
	}
	sort(a + 1, a + n + 1);
	int ans = 0;
	for (int i = 1; i * (k - 1) <= a[n]; i++)
	{
		ans = ans + solve(i);
		ans %= mod;
	}
	cout << ans;
	return 0;
}

B C2-与非门

题面

C C2-Zexal的钢管切割

题面描述

在钢管切割的背景下,已经知道长度为1−n的钢管的价值,给定长度为n的钢管在切割若干次(也可以不切割)所带来的最小价值是?

输入

多组数据输入

第一行一个整数n,为起始钢管长度(0<n≤1000)

第二行n个整数,分别为长度为i的钢管的价值ti(0<ti≤106)

输出

对于每组数据,输出一行,为这根钢管所带来的最小价值T

输入样例
3
2 3 7
输出样例
5
思路

算法导论第三版15.1节。书本例题求最大值,求最小值将max换为min即可

代码
脑残的化成了负值,为了用max思路。。
#include <iostream>
#include <cstdio>
int n;
int t[1010],f[1000001];
int max(int a,int b){
    return a>b?a:b;
}
int main() {
    while(~scanf("%d",&n)){
        f[0]=0;
        for(int i=1;i<=n;i++){
            scanf("%d",&t[i]);
            t[i]=-t[i];
        }
        for(int i=1;i<=n;i++){
            int q=-1000010;
            for(int j=1;j<=i;j++){
                q=max(q,t[j]+f[i-j]);
            }
            f[i]=q;
        }
        printf("%d\n",-f[n]);
    }
    return 0;
}

D C2-Zexel的流水线问题

题目描述

Zexal的偶像SkyLee趁着假期来逛漫展,漫展只有一条通道,只能从入口进入,出口离开,且左边有n个店铺,右边也有n个店铺,编号都是1~n。为了照顾大家没法兼顾逛两边的痛苦,左边和右边编号相同的店铺卖同样的周边。

现在SkyLee站在入口处的路中间,立志要从头到尾按顺序逛完所有的店铺。

因为每家店铺排队的人数不同,SkyLee在左边第i家要停留 p1[i] 的时间,在右边第i家要停留 p2[i] 的时间。而且这条路还挺宽的,所以从左边第i家移动到右边第i+1家需要t[1][i]的时间;从右边第i家移动到左边第i+1家需要t[2][i]的时间。

由于时间安排的紧,SkyLee想知道逛完漫展至少需要多长时间。

开始时从路中间到任意一边的时间以及同一边相邻店铺移动时间忽略不计。

输入

多组数据输入

对于每一组测试数据,第一行1个数 n (0<=n<=500)表示店铺数 。

接下来一行 n 个数,表示在左边店铺停留时间 p1 。再接下来一行n个数,表示在右边店铺停留时间 p2 (0<=p1,p2<=1000)。

接下来2行,每行n−1个数,分别表示 t[1][i] 和 t[2][i] (0<=t<=300)。

输出

对于每组数据,输出一行,为最少时间T。

输入样例
3
10 1 10
8 5 10
3 1  
1 3
输出样例
20
思路

课件例题,车间流水线。注意开始和结束时的时间安排,这题不耗时

代码
#include<stdio.h>
#define MAXN 501
int p1[MAXN],p2[MAXN];//当前店铺停留时间  
int t1[MAXN],t2[MAXN];//t1[i]:从左边第i家到右边第i+1家所需的移动时间  
int f[2][MAXN];//记录数组  
int Min(int a,int b);
int main()
{
    int n;//店铺数  
    while(scanf("%d",&n) == 1){
        int i;
        for(i = 1;i <= n;i++)
            scanf("%d",&p1[i]);
        for(i = 1;i <= n;i++)
            scanf("%d",&p2[i]);
        for(i = 1;i <= n-1;i++)
            scanf("%d",&t1[i]);
        for(i = 1;i <= n-1;i++)
            scanf("%d",&t2[i]);
        //初始化  
        f[0][1] = p1[1];
        f[1][1] = p2[1];
        //状态转移  
        int j;
        for(j = 2;j <= n;j++){
            f[0][j] = Min(f[0][j-1]+p1[j],f[1][j-1]+t2[j-1]+p1[j]);
            f[1][j] = Min(f[1][j-1]+p2[j],f[0][j-1]+t1[j-1]+p2[j]);
        }
        if(f[0][n] >= f[1][n])
            printf("%d\n",f[1][n]);
        else
            printf("%d\n",f[0][n]);
    }
}

int Min(int a,int b)
{
    if(a < b)
        return a;
    else
        return b;
}

E C2-Zexal的排座位

题目描述

在一个班级中挑选N个学生排成一列座位(保证有足够多的男生与足够多的女生),要求座位序列中男生互不相邻,求解有多少种排列方式?(挑选男生与女生的数量与排列方式均为任意)

例如挑选三个学生,那么所有排列为: 女女女、女男女,男女女,女女男,男女男

输入

第一个数为学生总数N(0<N<30)

输出

只有一行,保证男生与男生不相邻,座位排列的所有情况数目的结果

输入样例
3
输出样例
5
思路

已排好n个座位,第n+1个座位的性别根据第n个座位的性别做出选择,故n+1的座位的排序方法由n个座位的排序方法得来。

代码
#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
const int ms = 50;
ll res[ms][2];
int main(){
	res[1][0] = res[1][1] = 1;
	for(int i = 2; i <= 30; ++i){
		res[i][0] = res[i - 1][0] + res[i - 1][1];
		res[i][1] = res[i - 1][0];
	}
	int n;
	while (cin >> n){
		cout << res[n][0] + res[n][1] << "\n";
	}
	return 0;
}

F C2-Zexal的竞赛

题目描述

在一场竞赛中有n道题目,每道题都会对应一个分值,你可以选择任意一道题作答,比如你选择了x分的题目,那么在作答完毕(假设一定可以得分)后,你将获得x分,但是这场比赛中分值等于x−1和x+1的其他题目就会消失,那么这场比赛中你最多可以得到多少分?

输入

第一个数为题目总数 n0<n<1e5)n(0<n<1e5)
接下来为 nn 个整数 a1a2a3.....(0<ai<1e5)a1,a2,a3.....(0<ai<1e5)

输出

输出你可以得到的最高分

输入样例
9
1 2 1 3 2 2 2 2 3
输出样例
10
样例解释
每次都选择2 选择5次即可得到10分 1和3根据题目要求会消失
思路

当选择第n时,考虑第n-1个是否选了。
这样看是一个经典的dp问题。

if(i == 0) dp[i] = 0;
if(i==1) dp[i]=num[i];
if(i>1) dp[i] = max(dp[n-2]+num[i],dp[n-1])
代码
#include<iostream>
#include<cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int ms = 1e5 + 10;
int cnt[ms], dp[ms][2];
int main()
{
int n, a;
cin >> n;
for (int i = 0; i < n; ++i)
{
cin >> a;
cnt[a]++;
}
for (int i = 1; i < ms; ++i)
{
dp[i][0] = max(dp[i - 1][1], dp[i - 1][0]);
dp[i][1] = dp[i - 1][0] + cnt[i] * i;
}
cout << max(dp[ms - 1][0], dp[ms - 1][1]);
return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章