【P3817 小A的糖果
小A有N个糖果盒,第i个盒中有a[i]颗糖果。
小A每次可以从其中一盒糖果中吃掉一颗,他想知道,要让任意两个相邻的盒子中加起来都只有x颗或以下的糖果,至少得吃掉几颗糖。
【贪心策略】:
因为吃后面的可以影响后面的情况。所以一旦不满足就吃后面的即可。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N = 1e5+10; 5 ll a[N] , n , x ; 6 int main() 7 { 8 ios_base :: sync_with_stdio(false); 9 cin.tie(NULL) , cout.tie(NULL) ; 10 cin >> n >> x ; 11 for( int i=1 ; i<=n ;i++ ) 12 cin >> a[i] ; 13 ll ans = 0 ; 14 for( int i=1; i<=n-1 ;i++ ){ 15 if( a[i] + a[i+1] > x ){ 16 ll tmp = (a[i]+a[i+1])-x ; 17 a[i+1] = max( a[i+1] - tmp , 0ll ); 18 ans += tmp ; 19 } 20 } 21 cout << ans << endl; 22 return 0; 23 }
【P1094 纪念品分组】
元旦快到了,校学生会让乐乐负责新年晚会的纪念品发放工作。为使得参加晚会的同学所获得 的纪念品价值相对均衡,他要把购来的纪念品根据价格进行分组,但每组最多只能包括两件纪念品, 并且每组纪念品的价格之和不能超过一个给定的整数。为了保证在尽量短的时间内发完所有纪念品,乐乐希望分组的数目最少。
你的任务是写一个程序,找出所有分组方案中分组数最少的一种,输出最少的分组数目。
【贪心策略】
双指针算法,排序后,一个指着前面一个指着后面,如果后面放一个,看前面能放多少个,直到放不了为止就下一个盒子。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N = 3e4+20; 4 int a[N]; 5 int n,w; 6 int main() 7 { 8 ios_base :: sync_with_stdio(false); 9 cin.tie(NULL) , cout.tie(NULL); 10 cin >> w >> n ; 11 for(int i=1;i<=n;i++) cin >> a[i] ; 12 sort( a+1 , a+1+n ); 13 int p1 = 1 , p2 = n ; 14 int ans = 0 ; 15 while( p1 <= p2 ){ 16 if( a[p1] + a[p2] <= w ){ 17 p1 ++ , p2 --; 18 }else{ 19 p2 -- ; 20 } 21 ans ++; 22 } 23 cout << ans << endl; 24 return 0; 25 }
田忌赛马问题:但是通过两个指针分别指着两个不同的组。
1、如果 我队最弱的 > 对方最弱的 +2
2、如果 我方最强的 > 对方最强的 +2
3、如果送人头时发现,我方最弱 > 对方最强的 +1
剩下来就去送人头即可。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 //泡泡堂 2 #include<bits/stdc++.h> 3 using namespace std; 4 const int N = 1e5+10; 5 int n, a[N],b[N] ; 6 int solve( int a[] , int b[] ){ 7 int H1 = 1 , T1 = n ; 8 int H2 = 1 , T2 = n ; 9 int res = 0; 10 11 while( H1 <= T1 && H2 <= T2 ){ 12 if( a[H1] > b[H2] ){ 13 res += 2 ; 14 H1 ++ , H2 ++ ; 15 }else if( a[T1] > b[T2] ){ 16 res += 2 ; 17 T1 -- , T2 -- ; 18 }else{ 19 if( a[H1] == b[T2] ) res ++ ; 20 H1 ++ , T2 -- ; 21 } 22 } 23 return res ; 24 } 25 26 27 int main() 28 { 29 scanf("%d",&n); 30 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 31 for(int i=1;i<=n;i++) scanf("%d",&b[i]); 32 sort( a+1 , a+n+1 ); 33 sort( b+1 , b+n+1 ); 34 int ans1 = solve( a , b ); 35 int ans2 = 2*n - solve( b , a); 36 printf("%d %d\n",ans1,ans2); 37 return 0; 38 }
【P5019 铺设道路】
【题解】:来自洛谷的题解区的说法以及配图
https://www.luogu.org/problemnew/solution/P5019
贪心策略
若a[i]>a[i-1],计数器sum+=a[i]-a[i-1];
贪心证明
假设现在有一个坑,但旁边又有一个坑。
你肯定会选择把两个同时减1;
那么小的坑肯定会被大的坑“带着”填掉。
大的坑也会减少a[i]-a[i-1]的深度,可以说是“免费的”;
所以这样贪心是对的;
6
4 3 2 5 3 5
把道路画出来
【P1223 排队接水】
【题解】
这个题目其实是需要认真读题才行。
可以类比日常中的现象就行了。
比如我经常去剪头发,其实这个如果前面有两位小姐姐去剪头发,而我需要等待至少2个小时的时间去剪。但是我剪头发却只需要3~5分钟。那么是不是浪费我很多时间呢?对于整体我们三个人来说其实我们的平均花费时间是很大的,这个其实和操作系统中的调度算法,页面置换都是一个道理,我们先进先出必定是最失败的。如果采用短作业优先。那么就会整体提高这个大家的效率。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<cstdio> 2 #include<algorithm> 3 #include<map> 4 using namespace std; 5 const int N = 1e4+10; 6 typedef struct Node{ 7 int val,No; 8 bool operator < ( const Node &rhs ) const { 9 return ( val < rhs.val 10 || (val==rhs.val&&No<rhs.No) ); 11 } 12 }Node; 13 Node a[N]; 14 int main() 15 { 16 int n; 17 double sum=0; 18 scanf("%d",&n); 19 map<int ,int >my; 20 for(int i=1;i<=n;i++){ 21 scanf("%d",&a[i].val); 22 a[i].No = i ; 23 } 24 sort(a+1,a+1+n); 25 int every=0; 26 for(int i=1;i<=n;i++){ 27 printf("%d%c",a[i].No,i==n?'\n':' '); 28 if(i!=1){ 29 every+=a[i-1].val; 30 } 31 sum+=every; 32 } 33 printf("%.2lf\n",sum/(n*1.0)); 34 return 0; 35 }
【P1803 凌乱的yyy / 线段覆盖】
【题解】
经典贪心模型,线段覆盖问题
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N = 2e6+20; 4 typedef struct Line{ 5 int S,E; 6 bool operator < (const Line &rhs ) const { 7 if( E == rhs.E ) 8 return S < rhs.S; 9 return ( E < rhs.E ); 10 } 11 }Node; 12 Node a[N]; 13 int n; 14 int main() 15 { 16 cin >> n ; 17 for( int i = 1 ; i <= n ; i++ ){ 18 cin >> a[i].S >> a[i].E; 19 } 20 sort( a+1 , a+1+n ); 21 int E = 0 ,ans = 0 ; 22 for( int i=1 ; i <= n ; i++ ){ 23 if( E <= a[i].S ){ 24 E = a[i].E; 25 ans ++ ; 26 } 27 } 28 cout << ans << endl ; 29 return 0; 30 }
【P2060 [HNOI2006]马步距离】
【题解】
这个题目其实挺不错的,我之前就遇到过,但是没想到正确的代码如此小,而且非常好理解。
大家需要注意一点的是,这个棋盘是无限大的,但是如果遇到有限的棋盘的情况下其实是不可以这样通过打表的方式做的。主要是因为有些边界是无法走而导致最小的步数走不出来。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 int Step[5][5]={ 4 {0,3,2,3,2}, 5 {3,2,1,2,3}, 6 {2,1,4,3,2}, 7 {3,2,3,2,3}, 8 {2,3,2,3,4} 9 }; 10 int main(){ 11 int sx,sy,ex,ey,x,y; 12 cin >> sx >> sy >> ex >> ey ; 13 x = abs( sx - ex ); 14 y = abs( sy - ey ); 15 if( x < y ) swap(x,y); 16 int ans = 0 ; 17 while( x>4 || y>4 ){ 18 19 if( x < 0 ) x = -x ; 20 if( y < 0 ) y = -y ; 21 if( x < y ) swap( x , y ) ; 22 x -= 2 ; 23 y -= 1 ; 24 ans ++ ; 25 } 26 printf("%d\n",ans+Step[x][y]); 27 return 0; 28 }
【P1645 序列】
说句老实话吧,这个题其实就是省赛那道题目,我真的对不起队友,要是我当初好好在寒假学习一下,立即就是银牌了。真的对不起队友,真的十分懊悔,懊悔。懊悔。
就是多条覆盖线,然后满足最少的放法。真的对不起大家,认真训练真的非常重要。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N = 1e5+10; 4 int vis[N],n; 5 typedef struct Node{ 6 int L , R , C ; 7 bool operator < ( const Node &rhs ) const { 8 return R < rhs.R ; 9 } 10 }Node ; 11 Node a[N]; 12 int main(){ 13 cin >> n ; 14 for( int i=1 ; i<=n ; i++ ){ 15 cin >> a[i].L >> a[i].R >> a[i].C ; 16 } 17 sort ( a+1 , a+1+n ); 18 int t ; 19 int ans = 0 ; 20 for( int i=1 ; i<=n ; i++ ){ 21 //cout << a[i].L << " " << a[i].R << endl; 22 t = a[i].C ; 23 for(int j=a[i].L ; t && j <= a[i].R ; j++ ){ 24 if( vis[j] ) t--; 25 } 26 for(int j=a[i].R ; a[i].L<=j && t ; j-- ){ 27 if( vis[j]==0 ) { 28 vis[j] = 1 ; 29 t--; 30 ans++; 31 //printf("#### %d ### \n",j); 32 } 33 } 34 } 35 36 printf("%d\n",ans); 37 return 0; 38 }
【P2142 高精度减法】
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N = 1e6+10; 4 int a[N],b[N],c[N],n,m; 5 char s[N],t[N]; 6 bool Is_Minus(){ 7 if( n < m ) return true ; 8 if( n > m ) return false ; 9 if( n == m ){ 10 return strcmp( s , t ) < 0 ; 11 } 12 } 13 int main() 14 { 15 scanf("%s%s",s,t); 16 n = strlen(s) , m = strlen(t) ; 17 for(int i=0;s[i];i++) a[i] = s[i] - '0'; 18 for(int i=0;t[i];i++) b[i] = t[i] - '0'; 19 20 if( strcmp(s,t) == 0 ){ 21 printf("0\n"); 22 return 0 ; 23 } 24 25 26 reverse ( a , a+n ); 27 reverse ( b , b+m ); 28 29 30 if( Is_Minus() ){ 31 printf("-"); 32 swap( n , m ); 33 swap( a , b ); 34 } 35 /* 36 printf("%d %d \n",n,m); 37 for( int i = 0 ; i < n ;i++ ){ 38 printf("%d%c",a[i],i==n-1?'\n':' '); 39 } 40 for( int i = 0 ; i < n ;i++ ){ 41 printf("%d%c",b[i],i==n-1?'\n':' '); 42 } 43 */ 44 for(int i=n-1;i>=0;i--){ 45 if( a[i] - b[i] >= 0 ){ 46 c[i] = a[i] - b[i] ; 47 }else{ 48 c[i] = 10 + a[i] - b[i] ; 49 for(int j=i+1;j<n;j++){ 50 if( c[j] ){ 51 c[j]-- ; 52 break; 53 }else{ 54 c[j] = 9 ; 55 } 56 } 57 } 58 } 59 bool Front_Zero = true; 60 for(int i=n-1;i>=0;i--){ 61 if( c[i] == 0 && Front_Zero ){ 62 continue; 63 }else{ 64 Front_Zero = false ; 65 } 66 printf("%d",c[i]); 67 } 68 puts(""); 69 return 0; 70 }