[每日随题11] 贪心 - 数学 - 区间DP
整体概述
- 难度:1000 \(\rightarrow\) 1400 \(\rightarrow\) 1600
P3918 [国家集训队] 特技飞行
- 
标签:贪心 
- 
前置知识:无 
- 
难度:橙 1000 
题目描述:

输入格式:


输出格式:

样例输入:
5 2
2 2
样例输出:
12
解题思路:
- 
发现一次操作没有贡献,至少要两次操作。同时发现无论操作多少次,总贡献等同于只操作第一次和最后一次带来的贡献。 
- 
所以我们让价值最大的贡献操作时间最长即可,即将 \(c\) 从大到小排序,然后依次填充在头尾,模拟一遍计算总贡献即可。 
完整代码
#include<bits/stdc++.h>
#define Size(x) ((int)(x).size())
#define int long long
using namespace std;
const int N = 1e3+5;
int n,k,a[N],c[N];
signed main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin >> n >> k;
	for(int i=1;i<=k;i++) cin >> c[i];
	sort(c+1,c+k+1,[&](int x,int y){return x>y;});
	int res = 0;
	for(int i=1,j=1;i<=k && j<=n/2;i++,j++)
		res += ((n-j+1) - j)*c[i];
	cout << res;
	return 0;
}
P11465 水上舞者索尼娅
- 
标签:数学 
- 
前置知识:逆元 
- 
难度:黄 1400 
题目描述:

输入格式:


输出格式:

样例输入:
3
2 2
3 1
12 34
样例输出:
12
14
178629506
解题思路:
- 
我们发现,对于一张还剩 \(i\) 次的 \(一串香蕉\),在场上由 \(k\) 个索尼娅的时候,本质是使用了 \(k+1\) 张还剩 \(i\) 次的 \(一串香蕉\),随后产生 \(k+1\) 张还剩 \(i-1\) 次的 \(一串香蕉\)。 
- 
那么总使用次数即 \((k+1) + (k+1)^2 + ... + (k+1)^n\),用等比数列求和即 \(\frac {(k+1)*(1-(k+1)^n)} {1-(k+1)} = \frac {(k+1)*((k+1)^n-1)} {k}\)。 
- 
注意在模意义下除 \(k\) 是乘以 \(k\) 的逆元即可, 
完整代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod = 1e9+7;
int n,k;
inline int qpow(int a,int b){
	int res = 1;
	for(;b;b>>=1,a=a*a%mod)
		if(b&1) res=res*a%mod;
	return res;
}
inline void solve(){
	cin >> n >> k;
	cout << ((k+1)*(qpow(k+1,n)-1))%mod*(qpow(k,mod-2))%mod << '\n';
}
signed main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int T; cin >> T;
	while(T--) solve();
	return 0;
}
P6457 [COCI 2006/2007 #5] IVANA
- 
标签:区间DP 
- 
前置知识:拆环成链 
- 
难度:绿 1800 
题目描述:

输入格式:

输出格式:

样例输入:
3
3 1 5
4
1 2 3 4
8
4 10 5 2 9 8 1 7
样例输出:
3
2
5
解题思路:
- 
首先发现是环上的操作,我们先翻个倍拆环成链。 
- 
由于每次操作都是在已选择的区间的边缘上进行操作,我们考虑区间 \(DP\),题目所求的是奇数个数更多的玩家获胜,那么我们定义 \(dp_{i,j}\) 表示当前先手取完区间 \([i,j]\) 此时先手最多比后手多几个奇数。 
- 
那么 \(dp_{i,j} = max(dp_{i,i}-dp_{i+1,j},dp_{j,j}-dp_{i,j-1})\),全部更新一遍即可。 
- 
最后统计的时候需要注意,我们需要枚举先手取的起始点 \(i\),若 \(dp_{i,i} - dp_{i+1,i+n-1} \gt 0\) 则满足题意则统计答案。 
完整代码
#include<bits/stdc++.h>
#define Size(x) ((int)(x).size())
#define int long long
using namespace std;
const int N = 205;
int n,m,a[N],dp[N][N];
signed main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin >> n; m = n*2;
	for(int i=1;i<=n;i++) cin >> a[i], a[i+n] = a[i];
	for(int l=1;l<=m;l++) if(a[l]&1) dp[l][l] = 1;
	for(int len=2;len<=n;len++){
		for(int l=1;l<=m-len+1;l++){
			int r = l+len-1;
			dp[l][r] = max(dp[l][l]-dp[l+1][r],dp[r][r]-dp[l][r-1]);
		}
	}
	int res = 0;
	for(int i=1;i<=n;i++) if(dp[i][i] - dp[i+1][i+n-1] > 0) res += 1;
	cout << res;
	return 0;
}

![[每日随题11] 贪心 - 数学 - 区间DP](https://img2024.cnblogs.com/blog/3525992/202507/3525992-20250719220130286-645101968.png) 今天的简单~
        今天的简单~
     
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号