列输入一组数据a在2x地处起.然而那只跑的奶牛。

题意:电脑记录了某个一样随时每个赛车的前面和后个出些许辆车(多个车并排时在别的车那只算是一辆),问尽少生略个非客观的多寡。

Problem 1 抓牛(catchcow.cpp/c/pas)

解析:看到n<=1000经常,就尽量往DP上惦记吧。 

【题目叙述】

诸输入一组数据a,b,如果a+b>=n肯定很,加上自己虽跳n了。否则是车肯定在(a+1,n-b)这段距离内,所以马上段距离内之车子数(cnt[][]记录)++,如果自行车数超过区间长度,就不再加了。搞完输入数据后,再来DP:

       农夫约翰给打招呼,他的同样一味奶牛逃逸了!所以他控制,马上起身,尽快将那么只是奶牛抓回来.

定义:dp[i] :前 i
部车太多发生小车位置合理

他们还立在数轴上.约翰以N(O≤N≤100000)处,奶牛在K(O≤K≤100000)处.约翰有三三两两种植艺术运动,步行与瞬移:步行每秒种可以被约翰从x处走至x+l或x-l处;而瞬移则可让他当1秒内打x处消失,在2x地处起.然而那只跑的奶牛,悲剧地没有发现自己的地步多么糟糕,正站在当年一动辄不动.

则发方程: dp[i] =
min(dp[j]+cnt[j+1][i]) (0<= j < i )

       那么,约翰需要多少时引发那只牛为?

即前 i 部车太多的客体位置车数等于前 j
部车太多合理位置车数加上 j~i
这段位置被之成立位置车数(cnt[][]记录的还是合理合法位置车数)

【输入格式】

代码:

偏偏发生半点独整数N和K

图片 1图片 2

【输出格式】

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define N 1507

int dp[N];
int cnt[N][N];

int main()
{
    int cs = 1,n,i,j;
    int a,b;
    while(scanf("%d",&n)!=EOF && n)
    {
        memset(cnt,0,sizeof(cnt));
        memset(dp,0,sizeof(dp));
        for(i=1;i<=n;i++)
        {
            scanf("%d%d",&a,&b);
            if(a+b >= n)
                continue;
            cnt[a+1][n-b]++;
            if(cnt[a+1][n-b] > n-b-a)   //不能超过区间长度
                cnt[a+1][n-b] = n-b-a;
        }
        for(i=1;i<=n;i++)
        {
            for(j=0;j<i;j++)
            {
                dp[i] = max(dp[i],dp[j]+cnt[j+1][i]);
            }
        }
        printf("Case %d: %d\n",cs++,n-dp[n]);
    }
    return 0;
}

尽短日

View Code

【样例输入】

5 17

【样例输出】

4

 

【题解】

广搜次了

 

图片 3图片 4

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cstdlib>
 5 #include <algorithm>
 6 
 7 inline void read(int &x){x = 0;char ch = getchar();char c = ch;while(ch > '9' || ch < '0')c = ch, ch = getchar();while(ch <= '9' && ch >= '0')x = x * 10 + ch - '0', ch = getchar();if(c == '-')x = -x;}
 8 const int INF = 0x3f3f3f3f;
 9 const int MAXN = 400000;
10 
11 int n,k;
12 int b[MAXN][3];
13 //状态标号:0:x+1  1:x - 1  2:x * 2 
14 struct Node
15 {
16     int x,flag,step;
17 }queue[2500000];
18 int head,tail;
19 int ans;
20 
21 inline void bfs()
22 {
23     //[head, tail]
24     if(n >= k)
25     {
26         ans = n - k;return;
27     }
28     if((n + 1 == k || n - 1 == k) || ((n << 1) == k))
29     {
30         ans = 1;return;
31     }
32     head = 1, tail = 0;
33     queue[++tail] = Node{n - 1, 0, 1};
34     queue[++tail] = Node{n + 1, 1, 1};
35     queue[++tail] = Node{(n << 1), 2, 1};
36     b[n - 1][0] = true;
37     b[n + 1][1] = true;
38     b[(n << 1)][2] = true;
39     register Node tmp;
40     while(head <= tail)
41     {
42         tmp = queue[head ++];
43         for(int i = 0;i < 3;++ i)
44         {
45             if(i == 0 && tmp.x - 1 >= 0 && !b[tmp.x - 1][0])
46             {
47                 if(tmp.x - 1 == k)
48                 {
49                     ans = tmp.step + 1;
50                     return;
51                 }
52                 queue[++tail] = Node{tmp.x - 1, 0, tmp.step + 1};
53                 b[tmp.x - 1][0] = true;        
54             }
55             else if(i == 1 && tmp.x + 1 <= 200000 && !b[tmp.x + 1][1])
56             {
57                 if(tmp.x + 1 == k)
58                 {
59                     ans = tmp.step + 1;
60                     return;
61                 }
62                 queue[++tail] = Node{tmp.x + 1, 1, tmp.step + 1};
63                 b[tmp.x + 1][1] = true;
64             }
65             else if(tmp.x * 2 <= 200000 && !b[(tmp.x << 1)][2])
66             {
67                 if((tmp.x << 1) == k)
68                 {
69                     ans = tmp.step + 1;
70                     return;
71                 }
72                 queue[++tail] = Node{(tmp.x << 1), 2, tmp.step + 1};
73                 b[(tmp.x << 1)][2] = true;
74             }
75         }
76     }
77 }
78 
79 int main()
80 {
81     read(n);read(k);
82     bfs(); 
83     printf("%d", ans);
84     return 0;
85 }

View Code

 

 

 

Problem 2 路面整修(grading.cpp/c/pas)

【题目叙述】

FJ打算好好修一下农场被有修崎岖之土路。按奶牛们的要求,修好后的路面高度应单调上升还是干燥下降,也就是说,高度上升及高度降低之路段未能够以起于修好的路中。
整漫长总长被分为了N段,N个整数A_1, … , A_N (1 <= N <=
2,000)依次描述了各国一样截路的可观(0 <= A_i <=
1,000,000,000)。FJ希望找到一个正要好含N个因素的莫升或者不降低序列B_1, … , B_N,作为修过的路途被每个路段的可观。由于拿各一样截路垫高或者开低一个单位之花一样,修路的总支出可以表示为:
|A_1 – B_1| + |A_2

  • B_2| + … + |A_N – B_N| 请而算一下,FJ在这项工程上的极其小支是有点。FJ向而管,这个开不见面超越2^31-1。【输入格式】
     第1行: 输入1个整数:N * 第2..N+1行: 第i+1行为1个整数:A_i

【输出格式】
第1履: 输出1个刚刚整数,表示FJ把路修成高度不腾还是可观不落之最好小花费

【样例输入】

7
1
3
2
4
5
3
9

【样例输出】

3

【样例解释】

FJ将率先独惊人为3之路段的万丈减少也2,将第二单惊人为3的路段的莫大增加至5,总消费也|2-3|+|5-3| = 3,并且每路段的可观也一个请勿跌序列
1,2,2,4,5,5,9。

 

 

【题解】

DP题。

【状态定义】

dp[i][j]表示前i个数,最后一个频繁以原数组中是第j大/小的无比小价。记录cnt[i]为第i大/小得数,num[i]也第i只位置的勤

【转移】
dp[i][j] = min{dp[i

  • 1][k] + abs(num[i] – cnt[j])} 1 <= k <= j

【优化】
1、状态更新是O(n)的,我们得就此mi[i][j]表示dp[i][1..j]的最小值
2、这里还有一个技术,我们可被dp[i][j]意味着前i个数,最后一个再三以原数组中是前j大
的绝小价
   转移有
   dp[i][j] =
min{dp[i][j – 1], dp[i – 1][j] + abs(num[i] –
cnt[j])} 
  
同时也可行使滚动数组进行优化

图片 5图片 6

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cstdlib>
 5 #include <algorithm>
 6 inline int min(int a, int b){return a > b ? b : a;}
 7 inline void read(int &x){x = 0;char ch = getchar();char c = ch;while(ch > '9' || ch < '0')c = ch, ch = getchar();while(ch <= '9' && ch >= '0')x = x * 10 + ch - '0', ch = getchar();if(c == '-')x = -x;}
 8 const int INF = 0x3f3f3f3f;
 9 const int MAXN = 2000 + 10;
10 
11 int dp[2][MAXN], num[MAXN], cnt[MAXN], recnt[MAXN],ans,n;
12 
13 int main()
14 {
15     read(n);
16     for(register int i = 1;i <= n;++ i)
17     {
18         read(num[i]);
19         recnt[i] = cnt[i] = num[i];
20     }
21     std::sort(cnt + 1, cnt + 1 + n);
22     std::sort(recnt + 1, recnt + 1 + n, std::greater<int>());
23     register int tmp = 1;
24     for(register int i = 1;i <= n;++ i)
25     {
26         for(register int j = 1;j <= n;++ j)
27         {
28             if(j == 1)
29                 dp[tmp][j] = dp[tmp ^ 1][j] + abs(cnt[j] - num[i]);
30             else
31                 dp[tmp][j] = min(dp[tmp][j - 1], dp[tmp ^ 1][j] + abs(cnt[j] - num[i]));
32         }
33         tmp ^= 1;
34     }
35     ans = dp[n & 1][n];
36     tmp = 1;
37     for(register int i = 1;i <= n;++ i)
38     {
39         for(register int j = 1;j <= n;++ j)
40         {
41             if(j == 1)
42                 dp[tmp][j] = dp[tmp ^ 1][j] + abs(recnt[j] - num[i]);
43             else
44                 dp[tmp][j] = min(dp[tmp][j - 1], dp[tmp ^ 1][j] + abs(recnt[j] - num[i]));
45         }
46         tmp ^= 1;
47     }
48     ans = min(ans, dp[n & 1][n]);
49     printf("%d", ans);
50     return 0;
51 }

View Code

 

 

Problem 3 教主的魔法(magic.cpp/c/pas)

【题目叙述】

教主最近学会了扳平栽神奇之魔法,能够如人头增长强。于是他准备演示为XMYZ信息组每个英雄看。于是N个英雄们又平等赖聚集于了旅,这次他们排成了一样列,被编号也1、2、……、N。

每个人之身高一开始还是休超1000底正整数。教主的魔法每次可将闭区间[L, R](1≤L≤R≤N)内的英武的身高全部丰富一个平头W。(虽然L=R时连无称区间的书规范,但咱可以认为是独自增加第L(R)个英雄的身高)

CYZ、光哥和ZJQ等人口无信仰教主的吧,于是他们有时候会问WD闭区间 [L, R] 内生略英雄身高超过等于C,以验证教主的魔法是否真的可行。M”,则随即有三单数字L

WD巨懒,于是他将此对的任务交了而。

【输入格式】

 第1表现两单整数N、Q。Q为问题往往和教主的施法数总和。

 第2推行有N个正整数,第i个数代表第i单英雄之身高。

 第3及第Q+2行每行有一个操作:

(1)若首先单字母为“、R、W。表示针对闭区间 [L, R] 内所有勇于之身高增长W。

(2)若首先个字母为“A”,则随着有三只数字L、R、C。询问闭区间 [L, R] 内发生略英雄之身高过等于C。

【输出格式】

     对每个“A”询问输出一行,仅包含一个整数,表示闭区间
[L, R] 内身高过等于C的英雄数。

 【样例输入】

5 3

1 2 3 4 5

A 1 5 4

M 3 5 1

A 1 5 4

【样例输出】

2

3

【数据范围】

【输入输出样例说明】

原先5个大胆身高也1、2、3、4、5,此时[1, 5]里头发生2独英雄的身高超过等于4。教主施法后变为1、2、4、5、6,此时[1, 5]内有3只大胆之身高过等于4。

【数据范围】

对30%的数据,N≤1000,Q≤1000。

对100%的数据,N≤1000000,Q≤3000,1≤W≤1000,1≤C≤1,000,000,000

 

【题解】

分块+二分开模板题,第一赖写分块。。常数优化及天际

图片 7图片 8

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cstdlib>
  5 #include <algorithm>
  6 #include <cmath>
  7 
  8 inline void read(int &x){x = 0;char ch = getchar();char c = ch;while(ch > '9' || ch < '0')c = ch, ch = getchar();while(ch <= '9' && ch >= '0')x = x * 10 + ch - '0', ch = getchar();if(c == '-')x = -x;}
  9 inline int min(int a, int b){return a < b ? a : b;}
 10 void put(int x){if (x < 0)x = ~x + 1, putchar('-');if (x > 9) put(x / 10);putchar(x % 10 + 48);}
 11 const int INF = 0x3f3f3f3f;
 12 const int MAXN = 1000000 + 10;
 13 
 14 int n,q;
 15 int squ[MAXN],num[MAXN],pos[MAXN],block,flag[MAXN],size;
 16 int L[MAXN],R[MAXN];
 17 
 18 //对第x个块进行重新排序 
 19 int resort(int x)
 20 {
 21     int l = L[x];
 22     int r = R[x];
 23     for(register int i = l;i <= r;++ i)
 24         squ[i] = num[i];    
 25     std::sort(squ + l, squ + r + 1);
 26 }
 27 
 28 //对第x个块快内进行二分查找,返回找到的长度 
 29 int find(int x, int k)
 30 {
 31     int l = L[x];
 32     int r = R[x];
 33     int last = r;
 34     int mid;
 35     while(l <= r)
 36     {
 37         mid = (l + r) >> 1;
 38         if(squ[mid] < k)l = mid + 1;
 39         else r = mid - 1; 
 40     } 
 41     return last - l + 1;
 42 }
 43 
 44 //区间修改,[ll,rr]增加k 
 45 inline void modify(int ll, int rr, int k)
 46 {
 47     //同一个块则暴力修改
 48     if(pos[ll] == pos[rr]) 
 49     {
 50         for(register int i = ll;i <= rr;++ i)
 51             num[i] = num[i] + k;
 52         resort(pos[ll]);
 53         return;
 54     }
 55 
 56     //不同的块先改左右两边
 57     register int l = pos[ll],r = pos[rr];
 58     if(L[l] < ll)
 59     {
 60         for(register int i = ll;i <= R[l];++ i)
 61                num[i] = num[i] + k;
 62            resort(l);
 63            ++ l;
 64     }
 65     if(R[r] > rr)
 66     {
 67         for(register int i = L[r];i <= rr;++ i)
 68             num[i] = num[i] + k;
 69         resort(r);
 70         -- r;
 71     }
 72     for(register int i = l;i <= r;++ i)
 73         flag[i] = flag[i] + k;
 74 }
 75 
 76 //区间查询,[ll,rr]查询k
 77 
 78 int ask(int ll, int rr, int k)
 79 {
 80     register int ans = 0;
 81     if(pos[ll] == pos[rr])
 82     {
 83         for(int i = ll;i <= rr;++ i)
 84             if(num[i] + flag[pos[i]] >= k)ans ++;
 85         return ans;
 86     }
 87     register int l = pos[ll],r = pos[rr];
 88     if(L[l] < ll)
 89     {
 90         for(register int i = ll;i <= R[l];++ i)
 91             if(num[i] + flag[pos[i]]>= k)ans ++;
 92         ++ l;
 93     }
 94     if(R[r] > rr)
 95     {
 96         for(register int i = L[r];i <= rr;++ i)
 97                if(num[i] + flag[pos[i]]>= k)ans ++;
 98            -- r;
 99     }
100     for(register int i = l;i <= r;++ i)
101         ans = ans + find(i, k - flag[i]);
102     return ans;
103 } 
104 
105 int main()
106 {
107     read(n);read(q);
108     
109     register char c;
110     register int tmp1,tmp2,tmp3;
111     
112     block = sqrt(n);
113     if(n % block)
114         size = n / block + 1;
115     else 
116         size = n / block;
117         
118     for(register int i = 1;i <= n;++ i)
119     {
120         read(num[i]);
121         pos[i] = (i - 1) / block + 1;
122         squ[i] = num[i];
123     }
124     for(register int i = 1;i <= size;++ i)
125         L[i] = (i - 1) * block + 1,R[i] = i * block;
126     if(R[size] > n)R[size] = n;
127     for(register int i = 1;i <= size;++ i)
128         resort(i);
129         
130     for(register int i = 1;i <= q;++ i)
131     {
132         c = getchar();while(c != 'M' && c != 'A')c = getchar();
133         read(tmp1);read(tmp2);read(tmp3);
134         if(c == 'M')modify(tmp1, tmp2, tmp3);
135         else put(ask(tmp1, tmp2, tmp3)), putchar('\n');
136     }
137     return 0;
138 }

View Code

 

相关文章