Markdownは初めてそれに慣れず、長い時間がかかりました。。。。。。
燃える紙カット
度度熊有一张纸条和一把剪刀。
纸条上依次写着 N 个数字,数字只可能是 0 或者 1。
度度熊想在纸条上剪 K 刀(每一刀只能剪在数字和数字之间),这样就形成了 K+1 段。
他再把这 K+1 段按一定的顺序重新拼起来。
不同的剪和接的方案,可能会得到不同的结果。
度度熊好奇的是,前缀 1 的数量最多能是多少。
入力
有多组数据,读到EOF结束。
对于每一组数据,第一行读入两个数 N 和 K 。
第二行有一个长度为 N 的字符串,依次表示初始时纸条上的 N 个数。
0≤K<N≤10000
所有数据 N 的总和不超过100000
アウトプット
对于每一组数据,输出一个数,表示可能的最大前缀 1 的数量。
サンプル
入力
5 1
11010
5 2
11010
アウトプット
2 3
#include <iostream> #include <cstring> #include <アルゴリズム> 名前空間std を使用します。 int num [ 100005 ]; int cmp(int a、int b){ a> bを返す; } int main(){ int n、k; while(scanf(" %d%d "、&n、&k)== 2 ){ 文字列s; cin >> s; int all = 0、i; // すべて1 for(i = 0 ; i <n; i ++) if(s [i] == ' 1 ')all ++ ; int pre = 0 ; // 先行する「連続1」 for(i = 0 ; i <n; i ++ ){ if(s [i] == ' 1 ')pre ++ ; さもなければ 壊れる; } int left1 = 0 ; // 'continuous 1'の後ろ if(pre!= all){ // 可能な文字列sはすべて1であることに注意してください for(i = n- 1 ; i> = 0 ; i -- ){ if(s [i] == ' 1 ')left1 ++ ; さもなければ 壊れる; } } memset(num、0、sizeof (num)); int j = 0、flag; // j:途中の「連続1」の数を示します for(i = pre; i <n-left1; i ++){ // 中央の「連続1」を格納し、num []を使用して flag = 0 を格納します。 while(s [i] == ' 1 ' && i < n){ num [j] ++ ; i ++ ; フラグ = 1 ; } if(フラグ)j ++ ; } sort(num、num + j、cmp); // 中央の「連続1」は、最大から最小にソートされます int sum = 0、cur = k; // cur:現在残っているナイフの数を示します // 貪欲な戦略を開始し、最初に真ん中に対処し、2つのナイフを残すように注意します。最初と最後のナイフは1つだけ削減できるためです for(i = 0 ; i <j && cur> 2 ; i ++){ // 中間の「連続1」では、2つのナイフを使用して 合計 + = num [i]; をカットする必要があります。 num [i] = 0 ; // 使用後、 cur- = 2を削除 ; } // 残りの最後の2つのナイフを判断する for(i = 0 ; i <j; i ++) if(num [i]!= 0)break ; // 途中でカットされていない最大の「連続1」を見つける if(cur> = 2){ // 残りのナイフ数> = 2の場合、num [i]、pre、left1、および3つの最大の2つです(理由:ドラフトで説明してください) if(pre <= left1 && pre <= num [i])sum + =(left1 + num [i]); else if(left1 <= pre && left1 <= num [i])sum + =(pre + num [i]); それ以外の場合 sum + =(left1 + pre); } else if(cur == 1){ // ナイフ の残りの数== 1、つまりk == 3、2つの場合:1.中央をカットする、2。尾をカットする(尾をカットする場合、最初の1接続できる) sum + = max(num [i]、pre + left1); } if(k == 0)printf(" %d \ n "、pre); // k == 0、これはヘッダーの「連続1」です それ以外の場合、 printf(" %d \ n " 、sum); } 0を返します。 }