3.2常用技巧精选(一) 挑战程序设计竞赛
来源:互联网 发布:广州优化公司 编辑:程序博客网 时间:2024/06/05 07:34
本文来自《挑战程序设计竞赛》3.2常用技巧精选(一)
1.尺取法
1.Subsequence(Poj 3061)
1.题目原文:
Description
Input
Output
Sample Input
210 155 1 3 5 10 7 4 9 2 85 111 2 3 4 5
Sample Output
23
Source
题目意思:给定长度为n的数列整数a[0],a[1],a[2]……,a[n-1]以及整数S。求出总和不小于S的连续子序列的长度的最小值。如果解不存在,则输出0.
2.解题思路1:
3.AC代码1:
#include <iostream>#include<algorithm>#include<cstdio>using namespace std;#define maxn 100005int n,S;int a[maxn];int sum[maxn+1];//sum[i]=a[0]+a[1]+……a[i-1]//a[s]+a[s+1]+a[s+2]+……a[t-1]=sum[t]-sum[s]void solve(){ int res=n; sum[0]=0; for(int i=0;i<n;i++){ sum[i+1]=sum[i]+a[i]; } if(sum[n]<S){ printf("0\n"); return; } for(int s=0;sum[s]+S<=sum[n];s++){ int t=lower_bound(sum+s,sum+n,sum[s]+S)-sum; res=min(res,t-s); } printf("%d\n",res);}int main(){ int t; scanf("%d",&t); while(t--){ scanf("%d%d",&n,&S); for(int i=0;i<n;i++){ scanf("%d",&a[i]); } solve(); } return 0;}
4.解题思路2:
5.AC代码2:
#include <iostream>#include<algorithm>#include<cstdio>using namespace std;#define maxn 100005int n,S;int a[maxn];int sum[maxn+1];void solve(){ int s=0,t=0,sum=0; int res=n+1; for(;;){ while(t<n&&sum<S){ sum+=a[t++]; } if(sum<S) break; res=min(res,t-s); sum-=a[s++]; } if(res>n){ //解不存在 res=0; } printf("%d\n",res);}int main(){ int t; scanf("%d",&t); while(t--){ scanf("%d%d",&n,&S); for(int i=0;i<n;i++){ scanf("%d",&a[i]); } solve(); } return 0;}
2.Jessica's Reading Problem(Poj 3320)
1.题目原文
Description
Jessica's a very lovely girl wooed by lots of boys. Recently she has a problem. The final exam is coming, yet she has spent little time on it. If she wants to pass it, she has to master all ideas included in a very thick text book. The author of that text book, like other authors, is extremely fussy about the ideas, thus some ideas are covered more than once. Jessica think if she managed to read each idea at least once, she can pass the exam. She decides to read only one contiguous part of the book which contains all ideas covered by the entire book. And of course, the sub-book should be as thin as possible.
A very hard-working boy had manually indexed for her each page of Jessica's text-book with what idea each page is about and thus made a big progress for his courtship. Here you come in to save your skin: given the index, help Jessica decide which contiguous part she should read. For convenience, each idea has been coded with an ID, which is a non-negative integer.
Input
The first line of input is an integer P (1 ≤ P ≤ 1000000), which is the number of pages of Jessica's text-book. The second line contains P non-negative integers describing what idea each page is about. The first integer is what the first page is about, the second integer is what the second page is about, and so on. You may assume all integers that appear can fit well in the signed 32-bit integer type.
Output
Output one line: the number of pages of the shortest contiguous part of the book which contains all ideals covered in the book.
Sample Input
51 8 8 8 1
Sample Output
2
Source
2.题目意思:
3.解法分析:
4.AC代码:
#include <iostream>#include<algorithm>#include<cstdio>#include<set>#include<map>using namespace std;#define maxp 1000005int P;int a[maxp];void solve(){ //计算全部知识点的总数 set<int> all; for(int i=0;i<P;i++){ all.insert(a[i]); } //知识点的总数 int n=all.size(); //利用尺取法求解 int s=0,t=0,num=0; map<int,int> count;//知识点→出现次数的映射 int res=P; for(;;){ while(t<P&&num<n){ if(count[a[t++]]++==0){ //出现新的知识点 num++; } } if(num<n) break; res=min(res,t-s); if(--count[a[s++]]==0){ //某个知识的出现次数是0 num--; } } printf("%d\n",res);}int main(){ scanf("%d",&P); for(int i=0;i<P;i++){ scanf("%d",&a[i]); } solve(); return 0;}
2.开关问题
1.Face The Right Way Poj 3276
1.题目原文
Description
Farmer John has arranged his N (1 ≤ N ≤ 5,000) cows in a row and many of them are facing forward, like good cows. Some of them are facing backward, though, and he needs them all to face forward to make his life perfect.
Fortunately, FJ recently bought an automatic cow turning machine. Since he purchased the discount model, it must be irrevocably preset to turn K (1 ≤ K ≤ N) cows at once, and it can only turn cows that are all standing next to each other in line. Each time the machine is used, it reverses the facing direction of a contiguous group of K cows in the line (one cannot use it on fewer than K cows, e.g., at the either end of the line of cows). Each cow remains in the same *location* as before, but ends up facing the *opposite direction*. A cow that starts out facing forward will be turned backward by the machine and vice-versa.
Because FJ must pick a single, never-changing value of K, please help him determine the minimum value of K that minimizes the number of operations required by the machine to make all the cows face forward. Also determine M, the minimum number of machine operations required to get all the cows facing forward using that value of K.
Input
Lines 2..N+1: Line i+1 contains a single character, F or B, indicating whether cow i is facing forward or backward.
Output
Sample Input
7BBFBFBB
Sample Output
3 3
Hint
Source
2.题目意思:
3.解法与思路分析
4.AC代码
#include <iostream>#include<cstdio>#include<cstring>using namespace std;#define maxn 5005int N;int dir[maxn];//0:F,1:Bint f[maxn];//区间[i,i+k-1]是否翻转//固定k,求对应的最小操作数//无解时,返回-1int calc(int K){ memset(f,0,sizeof(f)); int res=0; int sum=0;//f的和 for(int i=0;i+K<=N;i++){ //计算区间[i,i+K-1] if((dir[i]+sum)%2!=0){ //前端的牛面向后方 //sum为奇数时,第i头牛的方向与初始方向相反 //dir[i]为1时不需要翻转,dir[i]为0时需要翻转 //sum为偶数时,第i头牛的方向与初始方向相同 //dir[i]为1时需要翻转,dir[i]为0时不需要翻转 res++; f[i]=1; } sum+=f[i]; if(i-K+1>=0){ sum-=f[i-K+1]; } } //检查剩下的牛是否有面朝后方的情况 for(int i=N-K+1;i<N;i++){ if((dir[i]+sum)%2!=0){ //无解,因为机器不能让少于K头连续的牛转向 return -1; } if(i-K+1>=0){ sum-=f[i-K+1]; } } return res;}void solve(){ int K=1,M=N; for(int k=1;k<=N;k++){ int m=calc(k); if(m>=0&&M>m){ K=k; M=m; } } printf("%d %d\n",K,M);}int main(){ scanf("%d",&N); for(int i=0;i<N;i++){ char c; cin>>c; if(c=='F') dir[i]=0; else dir[i]=1; } solve(); return 0;}
2.Fliptile Poj 3279
1.题目原文
Description
Farmer John knows that an intellectually satisfied cow is a happy cow who will give more milk. He has arranged a brainy activity for cows in which they manipulate an M × N grid (1 ≤ M ≤ 15; 1 ≤ N ≤ 15) of square tiles, each of which is colored black on one side and white on the other side.
As one would guess, when a single white tile is flipped, it changes to black; when a single black tile is flipped, it changes to white. The cows are rewarded when they flip the tiles so that each tile has the white side face up. However, the cows have rather large hooves and when they try to flip a certain tile, they also flip all the adjacent tiles (tiles that share a full edge with the flipped tile). Since the flips are tiring, the cows want to minimize the number of flips they have to make.
Help the cows determine the minimum number of flips required, and the locations to flip to achieve that minimum. If there are multiple ways to achieve the task with the minimum amount of flips, return the one with the least lexicographical ordering in the output when considered as a string. If the task is impossible, print one line with the word "IMPOSSIBLE".
Input
Lines 2..M+1: Line i+1 describes the colors (left to right) of row i of the grid with N space-separated integers which are 1 for black and 0 for white
Output
Sample Input
4 41 0 0 10 1 1 00 1 1 01 0 0 1
Sample Output
0 0 0 01 0 0 11 0 0 10 0 0 0
Source
2.题目意思
3.解法与思路分析
首先,同一个格子翻转两次就会恢复原状,所以多次翻转是多余的。此外,翻转的格子相同时,次序是无关紧要的。因此总共有2^NM种翻转方法。4.AC代码
#include <iostream>#include<cstdio>#include<utility>#include<cstring>using namespace std;#define MAX_N 20#define MAX_M 20const int dx[]={-1,0,0,0,1};const int dy[]={0,1,0,-1,0};int M,N;int tile[MAX_M][MAX_N];int opt[MAX_M][MAX_N];//保存最优解int flip[MAX_M][MAX_N];//保存中间结果//查询(x,y)的颜色int get(int x,int y){ int c=tile[x][y]; for(int d=0;d<5;d++){ int x2=x+dx[d],y2=y+dy[d]; if(0<=x2&&x2<M&&0<=y2&&y2<N){ c+=flip[x2][y2]; } } return c%2;}//求出在第一行确定情况下的最小操作次数//若不存在返回-1int calc(){ for(int i=1;i<M;i++){ for(int j=0;j<N;j++){ if(get(i-1,j)!=0){ //(i-1,j)是黑色,必须翻转(i,j)这个格子 flip[i][j]=1; } } } //判断最后一行是否全白 for(int j=0;j<N;j++){ if(get(M-1,j)!=0){ return -1; } } //统计翻转的次数 int res=0; for(int i=0;i<M;i++){ for(int j=0;j<N;j++){ res+=flip[i][j]; } } return res;}void solve(){ int res=-1; //按照字典序尝试第一行的所有可能性 for(int i=0;i<1<<N;i++){ memset(flip,0,sizeof(flip)); for(int j=0;j<N;j++){ flip[0][N-1-j]=i>>j&1; } int num=calc(); if(num>=0&&(res<0||res>num)){ res=num; memcpy(opt,flip,sizeof(flip)); } } if(res<0){ printf("IMPOSSIBLE\n"); } else{ for(int i=0;i<M;i++){ for(int j=0;j<N;j++){ printf("%d%c",opt[i][j],j+1==N?'\n':' '); } } }}int main(){ scanf("%d%d",&M,&N); for(int i=0;i<M;i++){ for(int j=0;j<N;j++){ scanf("%d",&tile[i][j]); } } solve(); return 0;}补充一道例题,https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2459
5.坐标离散化
1.例题
1.题目原文
2.解题思路
3.代码
#include<algorithm>#include<cctype>#include<cmath>#include<cstdio>#include<cstdlib>#include<cstring>#include<iomanip>#include<iostream>#include<map>#include<queue>#include<string>#include<set>#include<vector>#include<cmath>#include<bitset>#include<stack>#include<sstream>using namespace std;#define INF 0x7fffffffconst int maxn=505;int dx[]={1,-1,0,0};int dy[]={0,0,1,-1};int W,H,N;int X1[maxn],X2[maxn],Y1[maxn],Y2[maxn];//填充用bool fld[6*maxn][6*maxn];//对x1和x2进行坐标离散化//返回离散化之后的宽度int compress(int *x1,int *x2,int w){ vector<int> xs; for(int i=0;i<N;i++){ for(int d=-1;d<=1;d++){ int tx1=x1[i]+d; int tx2=x2[i]+d; if(1<=tx1&&tx1<=W) xs.push_back(tx1); if(1<=tx2&&tx2<=W) xs.push_back(tx2); } } //排序去重 sort(xs.begin(),xs.end()); xs.erase(unique(xs.begin(),xs.end()),xs.end()); for(int i=0;i<N;i++){ x1[i]=find(xs.begin(),xs.end(),x1[i])-xs.begin(); x2[i]=find(xs.begin(),xs.end(),x2[i])-xs.begin(); } return xs.size();}void solve(){ //坐标离散化 W=compress(X1,X2,W); H=compress(Y1,Y2,H); //填充有直线的部分 memset(fld,0,sizeof(fld)); for(int i=0;i<N;i++){ for(int y=Y1[i];y<=Y2[i];y++){ for(int x=X1[i];x<=X2[i];x++){ fld[y][x]=true; } } } //求区域的个数 int ans=0; for(int y=0;y<H;y++){ for(int x=0;x<W;x++){ if(fld[y][x]) continue; ans++; //宽度优先搜索 queue<pair<int,int> > que; que.push(make_pair(x,y)); while(!que.empty()){ int sx=que.front().first; int sy=que.front().second; que.pop(); for(int i=0;i<4;i++){ int tx=sx+dx[i]; int ty=sy+dy[i]; if(tx<0||tx>=W||ty<0||ty>=H) continue; if(fld[ty][tx]) continue; que.push(make_pair(tx,ty)); fld[ty][tx]=true; } } } } printf("%d\n",ans);}int main(){ scanf("%d%d%d",&W,&H,&N); for(int i=0;i<N;i++){ scanf("%d",&X1[i]); } for(int i=0;i<N;i++){ scanf("%d",&X2[i]); } for(int i=0;i<N;i++){ scanf("%d",&Y1[i]); } for(int i=0;i<N;i++){ scanf("%d",&Y2[i]); } solve(); return 0;}补充一道题目:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0531
- 3.2常用技巧精选(一) 挑战程序设计竞赛
- 程序设计竞赛常用技巧精选
- 挑战程序设计竞赛 4.4常用技巧(二)
- 《挑战程序设计竞赛》3.2.1 常用技巧-尺取法 POJ3061 3320 2566 2739 2100(1)
- 《挑战程序设计竞赛》3.2.2 常用技巧-反转 POJ3276 3279 3185 1222
- 《挑战程序设计竞赛》3.2.3 常用技巧-弹性碰撞 POJ3684 2674
- 《挑战程序设计竞赛》3.2.4 常用技巧-折半枚举 POJ2785 3977 2549
- 《挑战程序设计竞赛》3.2.5 常用技巧-坐标离散化 AOJ0531(1RE)
- 《挑战程序设计竞赛》 读后感
- 挑战程序设计竞赛:三角形
- 《挑战程序设计竞赛》 读后感
- 挑战程序设计竞赛(1)
- 技巧 坐标离散化 (来自《挑战程序设计竞赛》P164)
- 《挑战程序设计竞赛》 坐标离散化技巧实现
- 每日一题 No.40 挑战程序设计竞赛
- 《挑战程序设计竞赛》阅读笔记一 之 ALDS1_1_A Insertion Sort
- 《挑战程序设计竞赛》阅读笔记一 之 ALDS1_1_C Prime Numbers
- 《挑战程序设计竞赛》阅读笔记一 之 ALDS1_1_D Maximum Profit
- HDU 3068 最长回文 [Manacher回文串]
- java学习日记_27:面向对象之main方法格式详细解释
- 简易购物车的实现
- JS
- androidstudio 不能删除build文件夹的解决办法
- 3.2常用技巧精选(一) 挑战程序设计竞赛
- 2017阿里android客户端校招笔试题
- JAVA网络应用基础
- error LNK2019: unresolved external symbol _WinMain@16 referenced in function ___
- 使用git提交项目到开源中国(gitosc)
- 小波和编程
- 2017校招去哪网,阿里,网易,中兴,华为笔试编程题五则(Python描述)
- Java集合ArrayList实现类的总结
- 漫水填充算法