A, B, C略(https://github.com/keroro520/ACM/tree/master/cf/cf%23241)
D.
/*
思路题 多if
题意:给一个正整数数列A. 问你这个数列至少可以拆成多少个等差数列. 拆的时候要连续.
如(8, 6, 4, 2, 1, 4, 7, 10, 2) 就可以拆成(8, 6, 4, 2), (1, 4, 7, 10), (2)
现在这个数列里面会出现 -1 ,表示这个位置的数未知,你可以用任意正整数替换.
所以,要求输出-1都被替换之后,这个数列至少可以拆成多少个等差数列.
分析:难点就是在必须ai > 0
一开始想了个错误贪心,先把一块儿一块儿的 -1 和起来成一个总和,如 -1 -1 -1 就合成-3;
再贪心对于当前的ai (ai>0) ,让它尽量属于前面的等差数列;
下一步就是把还没归到等差数列里的-x 归到已知的由正整数构成的等差数列里,归不了的就ans++
但这样的贪心遇到下面的数据就跪了:
-1 1 5 -1 7
意识到这样贪心不对就好办啦,换种贪心呗.
改为贪心当前-1尽量属于前面的等差数列
实现很简单,从左往右扫,记录pre 表前一个数,d公差,tmp1/tmp2分别表示pre之前有多少个-1,
pre之后到当前ai有多少个-1。
对于ai > 0时,根据(pre, d, tmp1, tmp2)看当前ai是否能归为前面的等差数列;
对于ai==-1时,如果d 已知,则能根据(pre, d)确定当前-1应该替换为pre + d
NA表示未知,如新开一个等差数列时d当然是未知的啦;刚开始扫描时和以-1起始新开等差数列时 pre也是未知的
有个坑,会超int...
*/
#include <stdio.h>
#define NA 1000000009LL
typedef long long ll;
int n;
ll a[200005];
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%I64d", &a[i]);
ll pre = NA, d = NA, tmp1 = 0, tmp2 = 0;
int ans = 1;
for(int i = 1; i <= n; i++) {
if(a[i] == -1) {
if(d == NA) tmp2++; //d未知,无法确定当前-1应该替换为啥
else {
if(pre + d <= 0) { //不能在同一个等差数列,新开一个,注意这时候是以-1开头,所以pre = NA
pre = d = NA, tmp2 = 1, tmp1 = 0, ans++;
} else pre += d; //替换-1后可以在同一个等差数列,-1替换为pre+d
}
} else {
if(pre == NA) pre = a[i]; tmp1 = tmp2, tmp2 = 0; //第一次遇到ai>0,一定要tmp1 = tmp2
else {
if(d == NA) {
if((a[i] - pre) % (tmp2 + 1) == 0) {
d = (a[i] - pre) / (tmp2 + 1);
if(1 + tmp1 * d <= pre) tmp1 = tmp2 = 0, pre = a[i];
else d = NA, pre = a[i], tmp1 = tmp2 = 0, ans ++;
} else {
d = NA, pre = a[i], tmp1 = tmp2 = 0, ans ++;
}
} else {
if(pre + d == a[i]) pre = a[i];
else d = NA, pre = a[i], tmp1 = tmp2 = 0, ans ++;
}
}
}
}
printf("%d\n", ans);
return 0;
}
E.
/*
图论 最短路
题意:无向带边权图,任意两点之间最多一条边。要求输出所有点对s->t的最多路所经过的所有边数。
深觉这道题的解法很妙啊. 写了个n*n*m的TLE了,想了很久不会做,看了大牛的代码,自己理解了一下。
[*] 先Floyd 求出所有(s,t)的最短路 //我当初写了个n * dijstra 是作了多大的死,虽说复杂度确实比Floyd有降
[*] 算出cnt[i][j] 表示i->j的最短路上有多少条i的邻接边
[*] 最后i->j的最短路经过的边数ans[i][j] 就等于 i->j最短路途径的所有点k的cnt[k][j]之和
是怎么想到cnt[i][j]这样的表示的呢? 求告知啊!
*/
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define MAXN 505
int e[MAXN][MAXN], dist[MAXN][MAXN], cnt[MAXN][MAXN];
int n, m;
int main()
{
scanf("%d %d", &n, &m);
memset(dist, 0x3F, sizeof dist);
for(int i = 1; i <= n; i++) dist[i][i] = 0;
for(int i = 0; i < m; i++) {
int u, v, w;
scanf("%d %d %d", &u, &v, &w);
e[u][v] = e[v][u] = dist[u][v] = dist[v][u] = w;
}
for(int k = 1; k <= n; k++)
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++) if(e[i][j]) {
for(int k = 1; k <= n; k++)
if(e[i][j] + dist[j][k] == dist[i][k]) cnt[i][k]++;
}
for(int i = 1; i <= n; i++)
for(int j = i+1; j <= n; j++) {
int ans = 0;
for(int k = 1; k <= n; k++)
if(dist[i][k] + dist[k][j] == dist[i][j])
ans += cnt[k][j];
printf("%d ", ans);
}
puts("");
return 0;
}