数组推导
- 当 b[i] == a[i]的情况下,数组 a 的和是最大的情况
- 当 b[i] == b[i-1]的时候,a[i] == 0 的情况下,数组 a 最小
#include<bits/stdc++.h>
using namespace std;
const int N = 105;
int a[N], b[N];
int n;
int main(){
int sum_max = 0, sum_min = 0;
cin >> n;
cin >> b[0];
sum_max = b[0];
sum_min = b[0];
for(int i = 1; i < n; i++){
cin>> b[i];
sum_max += b[i];
if(b[i] != b[i - 1]) sum_min += b[i];
}
cout << sum_max << endl << sum_min;
return 0;
}
非零段划分
参考
我们可以先做下面这个题,本题算是下面这个题的简化版本。
2014. 岛 - AcWing题库
#include<bits/stdc++.h>
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
const int N = 100005;
int h[N];
PII q[N];
int main(){
int n;
cin>>n;
for(int i = 1; i <= n; i++){
cin>>h[i];
}
n = unique(h + 1, h + n + 1) - h - 1;
h[n + 1] = 0;
for(int i = 1; i <= n; i++) q[i] = {h[i], i};
sort(q + 1, q + n + 1);
int res =1, cnt = 1;
for(int i = 1; i <= n; i++){
int k = q[i].y;
if (h[k - 1] < h[k] && h[k + 1] < h[k]) cnt -- ;
else if (h[k - 1] > h[k] && h[k + 1] > h[k]) cnt ++ ;
if(q[i].x != q[i + 1].x) res = max(res, cnt);
}
cout<<res;
return 0;
}
与岛屿问题类似,p 表示海平面高度,数组 a 表示山峰高度,非零段的数量表示岛屿数量。当海平面 p 都大于岛屿的高度时,此时海平面只有 0 个岛屿,当海平面逐渐下降,当山峰出现时,岛屿数++;当山谷出现时,两个山峰被连在一起,岛屿数–;当出现的山峰和相邻山峰高度相同的时候,两个山峰被连在一起,岛屿数–(这种情况可以和山谷合并)。
代码思路:
- 读入数据
- 去重,删除相邻相同元素(unique 函数)
- 遍历数组,同时做山峰和山谷的判断,得到对应高度的岛屿数量贡献数组
- 遍历岛屿数量贡献数组,寻找哪个高度能得到最多的岛屿数
- 输出
#include<bits/stdc++.h>
using namespace std;
const int N = 500005, M = 10005;
int a[N], cnt[M];
int n;
int main(){
cin>>n;
for(int i = 1; i <= n; i++){
cin>>a[i];
}
n = unique(a + 1, a + n + 1) - a - 1;
a[0] = a[n + 1] = 0;
for(int i = 1; i <= n; i++){
if(a[i - 1] < a[i] && a[i + 1] < a[i]) cnt[a[i]]++;
else if(a[i - 1] > a[i] && a[i + 1] > a[i]) cnt[a[i]]--;
}
int res = 0, sum = 0;
for(int i = M - 1; i; i--){
sum += cnt[i];
res = max(res, sum);
}
cout<<res;
return 0;
}
脉冲神经网络
[[邻接表]]
第 161 行的 mod 操作是对存储空间的优化,因为实际上在循环时间的时候我们需要用到的或者需要修改的数据是当前时间点和距离当前时间点延迟 d 后的时间,所以对于时间我们只需要维护一个长度为 d 的滚动数组即可。
第 125 行,关于二维数组 I,第一维度时间,d 的大小不超过 1000,但是因为为了使得地址连续(一个小优化)所以取为 1024,然后第二维度是神经元,因为只有神经元才需要记录,脉冲源不需要。
#include<bits/stdc++.h>
using namespace std;
const int N = 2010; //1000个脉冲源+1000个神经元
const double INF = 1e8;
int n, s, p, T;
double dt; //时间间隔
int h[N], e[N], D[N], ne[N],idx; // 神经元邻接表
double W[N], v[N], u[N], a[N], b[N], c[N], d[N];//v, u, a, b, c, d是神经元相关量
int r[N], cnt[N]; //cnt存储神经元释放脉冲的次数
double I[1024][N / 2]; //表示神经网络状态,第一维度是时间,第二维度是脉冲源或神经元的标号,表示t时间下i个脉冲源(神经元)的状态
static unsigned long _next = 1; //注意这里为了防止next和头文件中的某个next冲突,前面加个下划线
/* RAND_MAX assumed to be 32767 */
int myrand(void) {
_next = _next * 1103515245 + 12345;
return((unsigned)(_next/65536) % 32768);
}
void add(int a, int b, double c, int d){
e[idx] = b; W[idx] = c, D[idx] = d, ne[idx] = h[a], h[a] = idx++;
}
int main(){
memset(h, -1, sizeof h);
cin>>n>>s>>p>>T;
cin>>dt;
for(int i = 0; i < n;){
int rn;
cin>>rn;
double vv, uu, aa, bb, cc, dd;
cin>>vv>>uu>>aa>>bb>>cc>>dd;
for(int j = 0; j <rn; j++, i++){
v[i] = vv, u[i] = uu, a[i] = aa, b[i] = bb, c[i] = cc, d[i] = dd;
}
}
for(int i = n; i < n + p; i ++) cin>>r[i];
int mod = 0;
while(s -- ){
int a, b, d;
double c;
cin>>a>>b>>c>>d;
add(a, b, c, d); //构建神经元图
mod = max(mod, d + 1);//此处是对空间的优化
}
for(int i = 0; i < T; i ++){
int t = i % mod;
for(int j = n; j < n + p; j ++){//遍历脉冲源
if(r[j] > myrand()){
for(int k = h[j]; ~k; k = ne[k]){ //释放脉冲
int x = e[k];
I[(t + D[k]) % mod][x] += W[k];
}
}
}
for(int j = 0; j < n; j++){//遍历神经元
double vv = v[j], uu = u[j];
v[j] = vv + dt * (0.04 * vv * vv + 5 * vv + 140 - uu) + I[t][j];
u[j] = uu + dt * a[j] * (b[j] * vv - uu);
if(v[j] >= 30){
for (int k = h[j]; ~k; k = ne[k]) //释放脉冲
{
int x = e[k];
I[(t + D[k]) % mod][x] += W[k];
}
cnt[j]++;
v[j] = c[j], u[j] += d[j];
}
}
memset(I[t], 0, sizeof I[t]);
}
double minv = INF, maxv = -INF;
int minc = INF, maxc = -INF;
for (int i = 0; i < n; i ++ )
{
minv = min(minv, v[i]);
maxv = max(maxv, v[i]);
minc = min(minc, cnt[i]);
maxc = max(maxc, cnt[i]);
}
printf("%.3lf %.3lf\n", minv, maxv);
printf("%d %d\n", minc, maxc);
return 0;
}
收集卡牌
这道题是求解期望,所以直接使用期望公式概率 x 状态的和即可,重点是如何求解状态。
因为不同的状态之间有依赖关系,形成的结构很像是树,所以用 DP 来做。
我们将状态表示为 f (i, j),第一维度 i 表示选到了哪些牌(用位向量表示),第二个维度表示硬币数量,f (i, j) 就是在 i 的选牌,攒了 j 个硬币的情况下的期望。
#include<bits/stdc++.h>
using namespace std;
const int N = 16, M = 1 << N;
int n, m;
double p[N];
double f[M][N * 5 + 1]; //M表示取牌一共有2的16次方个情况,N * 5 + 1意思是N个牌,每个最多5个硬币,但是实际上攒够k硬币就会兑换牌,所以其实会有冗余。
double dp(int state, int coins, int r){ //抽到的牌,硬币数,没抽到的牌数量
auto& v = f[state][coins];
if(v >= 0) return v;
if(coins >= r * m) return v = 0;
v = 0;
for(int i = 0; i < n; i++){
if(state >> i & 1){
v += p[i] * (dp(state, coins + 1, r) + 1);
}else{
v += p[i] * ( dp((state | 1 << i), coins, r - 1) + 1);
}
}
return v;
}
int main(){
cin>>n>>m;
for(int i = 0; i < n; i++){
cin>>p[i];
}
memset(f, -1, sizeof f);
printf("%0.10lf\n", dp(0, 0, n));
return 0;
}