bzoj 1283
給出乙個長度為n的正整數序列ci,求乙個子串行,使得原序列中任意長度為m的子串中被選出的元素不超過k 個,並且選出的元素之和最大。
n<=1000,k,m<=100,ci<=20000。
分析把數列串成一串,從 i
ii 連向 i+m
i+mi+
m,費用cic_
ci,流量1
11。s
ss連1
11,流量k
kk即可。也即選擇乙個數之後,其後k
kk個之後便無影響。
loj 6079 山東集訓 養貓
限制改為連續m
mm個不超過k1k1
k1個,不少於k2k2
k2個分析
由於穿過每個截面的流量相同,要求上方有至少k2k2
k2個就是要求下方至多k1−
k2
k1-k2
k1−k
2個,在下方加乙個上界即可
zjoi 2013 防守戰線
每個位置的數可以選若干次,限制形如[l,
r]
[l, r]
[l,r
]中至少選k
kk個,求最小和
分析兩種理解方式:
(1)用差分的方法使得每個變數僅在兩個式子中出現,且係數一正一負。
這是一種經典的做法,從志願者招募一題開始出現。若是使用這種做法,需要係數矩陣每一列不為0的數連續且相等。如此例:
a1a2
a3a4
a5a601
1001
0111
0110
1111
1000
10這樣差分之後便使得每個變數出現兩次,且係數分別為±
1\pm1
±1。但本題中的性質則略有變化。本題為每一行的非零數連續且相同,如此例:
a1a2
a3a4
a5a601
1100
1111
0000
0011
1111
00所以我們需要將其旋轉90∘
90^\circ
90∘,也就是對偶。
對偶之後即可變為之前的圖,差分即可。
(2)用字首和轉化,方法同chefbook。
原線性規劃形如:
設s
is_i
si表示1−i
1-i1−
i選了幾個數
最小化 :
∑ (s
i−si
−1)∗
ci
\sum(s_i-s_)*c_i
∑(si−
si−1
)∗c
i滿足:sr−
sl−1
>=d
ks_r-s_ >= d_k
sr−sl
−1>=d
ks i−
si−1
>=0
s_i-s_i-1 >= 0
si−si
−1>=0
s
i>=0
s_i >= 0
si>=0
注意到每個限制都只有兩個變數,且引數分別為±
1\pm1
±1。如下例:
a1a2
a3a4
a5a60-1
0100
00-11
00-10
0001
-1010
00則將其對偶之後(行列交換),每個變數恰出現兩次,且係數分別為±
1\pm1
±1費用流即可
在3的基礎上,增加一種限制形如[l, r]中至多選k個,求最小/最大和
在4的基礎上,增加一種限制,每個位置有乙個至多選的次數,求最大/最小和
完整描述如下:
有乙個數列,在這個數列中選一些數。位置i
ii的數可以被選擇t
it_i
ti次。現在有若干限制,形如在區間[l,
r]
[l, r]
[l,r
]中至少/至多選出幾個數,求最小/最大和。
乙個數列,限制形如區間[l,
r]
[l, r]
[l,r
]的和至少為$d $,求最少選出幾個數。
//t1, bzoj1283
#include #include #include #include #include #include #define maxn 1050
#define il inline
#define pb push_back
#define ri register int
#define mod
#define inf (1<<28)
using namespace std;
typedef long long ll;
typedef long double ld;
struct node pool[maxn<<4], *h[maxn<<4], *pre[maxn<<4];
int n, m, k, cnt, w[maxn], s, t, maxf, minc, inq[maxn<<4], val[maxn<<4], c[maxn<<4], q[maxn<<5];
il void adde(int u, int v, int c, int w) , h[u] = p;
*q = node , h[v] = q;
}bool spfa() }}
if(val[t] <= -2e9) return 0;
maxf += val[t], minc += val[t]*c[t];
int u = t;
while(u != s)
return 1;
}int main()
###1-2
//t2 養貓
#include #include #include #include #include #include #include #include #include #include #define inf (1<<29)
#define llinf (1ll<<60)
#define maxn 5050
using namespace std;
/*第一行四個整數 n,k,ms,me
第二行包含 n n n 個整數,代表 si
第三行包含 n 個整數,代表 ei。*/
int n, k, ms, me, cnt, sl[maxn], ea[maxn], ss, s, t, maxn, minn, flow;
int q[maxn<<2], c[maxn<<2], inq[maxn<<2], go[maxn<<2];
long long sum, w[maxn<<2], fee;
struct nodepool[maxn<<4], *h[maxn<<2], *pre[maxn<<2];
inline void addedge(int u, int v, int c, int w, int ty) , h[u] = p1;
*p2 = node, h[v] = p2;
}bool spfa()
} }if(w[t] <= iiss) return 0;
flow += c[t], fee += w[t]*c[t];
int u = t;
while(u != ss)
return 1;
}int main()
for(int i = 1; i <= n; i++)
while(spfa());
printf("%lld\n", sum+fee);
for(int i = 1; i <= n; i++)
if(go[i]) printf("e");
else printf("s");
return 0;
}
NOIP提高組 選數問題
在麥克雷的面前有n個數,以及乙個r c的矩陣。現在他的任務是從n個數中取出r c個,並填入這個矩陣中。矩陣每一行的法值為本行最大值與最小值的差,而整個矩陣的法值為每一行的法值的最大值。現在,麥克雷想知道矩陣的最小法值是多少。顯然排序後選擇答案是不會影響答案的,分析題意後可以發現乙個明顯的性質 對於某...
week3 A 選數問題
given n positive numbers,select exactly k of them that sums to s.wonders how many ways to get it 給n個數,選擇k個數相加的和為s,找出所有數的組合。the first line,an integer t...
c 實現 遞迴選數問題
給定乙個陣列,裡面有n位正整數,要從這個陣列裡面選取k個數,使得它們的和為s,問有多少種可能的取法 第一行,乙個整數t t 100 指示測試用例的數量。對於每個情況,有兩行。第一行,三個整數表示n,k和s.其中k n 16.第二行n個整數表示n個元素的陣列。資料保證所有數字都可以以 32 位整數儲存...