题目:http://codeforces.com/contest/738
A 题意:给一个长度为n的字符串,如果碰到了ogo就变成***,ogo变成***,如果是ogogogo也只能变成***
思路:暴力填充
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; char str[110],tmp[110]; int main(){ int len; while(scanf("%d",&len)!=EOF){ for(int i=1;i<=len;i++){ scanf(" %c",&str[i]); } for(int i=1;i<=len;i++) tmp[i]=str[i]; int len1=0; for(int i=1;i<=len;i++){ bool flag=false; if(str[i]=='o'){ while(str[i+1]=='g'&&str[i+2]=='o'){ flag=true; i+=2; } if(flag){ tmp[len1++]='*'; tmp[len1++]='*'; tmp[len1++]='*'; } else tmp[len1++]=str[i]; } else tmp[len1++]=str[i]; } for(int i=0;i<len1;i++){ printf("%c",tmp[i]); } printf(" "); } return 0; }
B.题意:给一个n*m的矩阵,有一盏灯,矩阵里面有0和1,为0的地方可以放一盏灯,灯可以上下左右四个方向照,只能直线照,问有多少种放灯的方法使得至少能照到一个1.
思路:用树状数组维护在第i行的前缀和,和第j列的前缀和(其实直接前缀和就可以做,树状数组会多一个log),对于矩阵为0的点直接询问四个方向的和。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 using namespace std; 6 const int maxn=1010; 7 int G[maxn][maxn]; 8 int treecol[maxn][maxn]; 9 int treerow[maxn][maxn]; 10 void add(int k,int i,int m){ 11 while(i<=maxn){ 12 treecol[i][m]+=k; 13 i+=(i&(-i)); 14 } 15 } 16 int query(int i,int m){ 17 int sum=0; 18 while(i>0){ 19 sum+=treecol[i][m]; 20 i-=(i&(-i)); 21 } 22 return sum; 23 } 24 void add1(int k,int i,int m){ 25 while(i<=maxn){ 26 treerow[i][m]+=k; 27 i+=(i&(-i)); 28 } 29 } 30 int query1(int i,int m){ 31 int sum=0; 32 while(i>0){ 33 sum+=treerow[i][m]; 34 i-=(i&(-i)); 35 } 36 return sum; 37 } 38 int main(){ 39 int n,m; 40 while(scanf("%d %d",&n,&m)!=EOF){ 41 memset(treerow,0,sizeof(treerow)); 42 memset(treecol,0,sizeof(treecol)); 43 for(int i=1;i<=n;i++) 44 for(int j=1;j<=m;j++){ 45 scanf("%d",&G[i][j]); 46 if(G[i][j]){ 47 add(1,j,i); 48 add1(1,i,j); 49 } 50 } 51 int cnt=0; 52 for(int i=1;i<=n;i++){ 53 for(int j=1;j<=m;j++){ 54 if(!G[i][j]){ 55 if(query(j,i)) cnt++;//left 56 if(query(m+1,i)-query(j,i)) cnt++;//right 57 if(query1(i,j)) cnt++;//up 58 if(query1(n+1,j)-query1(i,j))cnt++;//down 59 } 60 } 61 } 62 printf("%d ",cnt); 63 } 64 return 0; 65 }
C:题意:有n辆车,每辆车有邮箱大小和租金,在0的位置开始到s为终点,路上有k个加油站,到加油站可以立刻使得邮箱充满,车子如果1min走1km,那么耗油为2,如果2min走1km,那么耗油为1,求在走到终点的时间不大于t情况下所需要的最小花费
思路:假设在0处和s处都有加油站,那么加油站把路径分成了几段,假设在s1这段时,车子以1km/min的速度走了x0 的长度,那么列一个方程(s1-x0)+2*x0=v,v是车子的邮箱容量,那么x0=v-len;那么这段所需要的时间就是x0+2*(s1-x0),就可以o(k)算出走完所需要的最短时间,然后二分油箱容量,最后选择一个满足邮箱条件价格最少的那辆车。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <cstdlib> 6 using namespace std; 7 int n,k,s,t; 8 const int maxn=2e5+10; 9 int pos[maxn]; 10 struct node { 11 int c,v; 12 }; 13 node car[maxn]; 14 bool cmp(node a,node b) { 15 return a.c<b.c; 16 } 17 bool judge(int v) { 18 int sum=0; 19 for(int i=1;i<=k+1;i++) { 20 int len=pos[i]-pos[i-1]; 21 if(len>v) return false; 22 int x0=v-len; 23 x0=min(len,x0); 24 sum+=(x0+2*(len-x0)); 25 } 26 return sum<=t; 27 } 28 int bin_search() { 29 int r=1e9+1; 30 int l=0; 31 int ansV=1e9+1; 32 while(l<=r) { 33 int mid=(l+r)>>1; 34 if(judge(mid)) { 35 ansV=min(ansV,mid); 36 r=mid-1; 37 } 38 else { 39 l=mid+1; 40 } 41 } 42 return ansV; 43 } 44 int main(){ 45 while(scanf("%d %d %d %d",&n,&k,&s,&t)!=EOF){ 46 for(int i=1;i<=n;i++) { 47 scanf("%d %d",&car[i].c,&car[i].v); 48 } 49 pos[0]=0; 50 pos[k+1]=s; 51 for(int i=1;i<=k;i++) { 52 scanf("%d",&pos[i]); 53 } 54 sort(pos,pos+2+k); 55 sort(car+1,car+1+n,cmp); 56 int V=bin_search(); 57 int ans=-1; 58 for(int i=1;i<=n;i++) { 59 if(car[i].v>=V) { 60 ans=car[i].c; 61 break; 62 } 63 } 64 printf("%d ",ans); 65 } 66 return 0; 67 }
D:题意:有一场海战,在1×n的矩形中进行,有a只船,(不会重叠),每条船的长度为b,Galya已经攻击了k次,但一条船都没有打中,并且知道这k次攻击的位置,问至少还要做多少次攻击才能打中至少一艘船,输出次数和攻击的位置
思路:贪心,在没打中的位置以每次长度为b的递加,递加到的那个点假设要攻击记录下来,假设0的位置没打中,n+1的位置没有打中,这样就把矩形划分成了几段,处理出所有攻击的点,这个时候如果全部攻击了是能打到所有船的,那么至少一艘,我们就可以是少打(a-1)次,因为攻击的位置都是等效的,那么我们少攻击(a-1)次,必然会击中一艘船
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 using namespace std; 6 int str[(int)2e5+10],n,a,b,k; 7 int pos[(int)2e5+10]; 8 int ans[(int)2e5+10]; 9 int main(){ 10 while(scanf("%d %d %d %d",&n,&a,&b,&k)!=EOF){ 11 int tot=1; 12 for(int i=1;i<=n;i++){ 13 scanf("%1d",&str[i]); 14 if(str[i]) pos[tot++]=i; 15 } 16 pos[0]=0; 17 pos[tot++]=n+1; 18 int pre=1; 19 int now=0; 20 pre=pos[0]; 21 k+=1; 22 tot=1; 23 while(k--){ 24 for(int i=pre;i+b<pos[tot];i+=b){ 25 ans[now++]=i+b; 26 } 27 pre=pos[tot++]; 28 } 29 printf("%d ",now-a+1); 30 for(int i=0;i<=now-a;i++){ 31 printf("%d%c",ans[i],i==now-a?' ':' '); 32 } 33 } 34 return 0; 35 }
E:题意:有n个职工其中有一个是主管,每个职工都有一个直接的上司,上司的上司也是他的上司,除了主管没有上司,现在给出每个人的上司有多少个,求最少有多少个错的
思路:贪心 如果出了上司还有0出现的话那肯定是错的,把他设为INF,然后这个序列成立的条件是每个数都跟前面相等或者比前面少一,如果出现断了的话,从后面补,如果不能补掉,那说明后面全部都是错的。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 using namespace std; 6 const int maxn=2e5+10; 7 struct node{ 8 int id; 9 int num; 10 }; 11 const int INF = 0x3f3f3f3f; 12 node a[maxn]; 13 bool cmp(const node&a,const node&b){ 14 return a.num<b.num; 15 } 16 int main(){ 17 int n,s; 18 while(scanf("%d %d",&n,&s)!=EOF){ 19 int cnt=0; 20 for(int i=1;i<=n;i++) { 21 scanf("%d",&a[i].num); 22 a[i].id=i; 23 if(a[i].num==0&&i!=s){ 24 a[i].num=INF; 25 //cnt++; 26 } 27 if(i==s&&a[i].num!=0){ 28 a[i].num=0; 29 cnt++; 30 } 31 } 32 sort(a+1,a+1+n,cmp); 33 for(int i=2;i<=n;i++){ 34 if(a[i].num==a[i-1].num||a[i].num==a[i-1].num+1) continue; 35 else { 36 int tmp=a[i].num-a[i-1].num-1; 37 if(n-i>=tmp) { 38 cnt+=tmp; 39 n-=tmp; 40 } else { 41 cnt+=(n-i); 42 cnt++; 43 break; 44 } 45 46 } 47 } 48 printf("%d ",cnt); 49 } 50 return 0; 51 }
F留坑