赏赏赏
Time Limit: 2000ms Memory limit: 65536K 有疑问?点这里^_^
题目描述
B国大举进犯,A国根据地利设下埋伏获得全胜,战后A国王论功行赏,现在问题来了。
现在我们将问题简化,已知B国一共来了M个士兵,每个士兵的生命值为Hi,A国设置了N个据点,当士兵经过第j个据点时,生命值减少Wj,当士兵的生命值小于等于0时就会被当前这个据点杀死。由于地形原因士兵必须依次经过据点1,据点2,据点3. . . . . .据点N。
现在A国王想知道前M个据点的杀敌数为多少。
输入
多组输入。
对于每组数据,首先输入两个整数N,M(1 <= N <= 100000,1 <= M<= min(N, 10000))。
接下来的M行,每行一个整数Hi,代表第i个士兵的初始生命值。(1 <= Hi <= 10000000)
接下来的N行,每行一个整数Wj,代表第j个据点的攻击力。(0 <= Wi <= 10000)
输出
对于每组数据。
输出M行,每行一个整数代表第j个据点的杀敌数。
示例输入
3 3 1 2 3 1 1 1
示例输出
1 1 1
这题的一个简单方法就是把士兵的生命值从小到大排序,把从第1个据点到第j个据点的攻击力总和算出来,与士兵的生命值进行比较,当士兵的生命值小于等于到第j个据点的攻击力总和时,士兵就会在第j个据点被杀死,该据点的杀敌数加1即可,这样可以省很多功夫。(这么简单的题我竟然因为cin和cout超时了好多次= =以后一定不忘加std::ios::sync_with_stdio(false);〒_〒)
代码
#include <cstdio> #include <algorithm> using namespace std; int h[1001000],w[1000000],cont[1000000]; int main() { int n,m,i,j; while(~scanf("%d%d",&n,&m)) { for(i=0; i<m; i++) scanf("%d",&h[i]); sort(h,h+m); for(i=0;i<n;i++) { scanf("%d",&w[i]); w[i]=(i==0?w[i]:w[i-1]+w[i]); } for(i=0;i<m;i++) cont[i]=0; for(i=0,j=0;i<m&&j<m;) { if(h[j]<=w[i]) { cont[i]++; j++; } else i++; } for(i=0;i<m;i++) printf("%d\n",cont[i]); } return 0; }
还有一种更简洁的办法,就是用二分查找的原理,通过lower_bound()这个函数来查找士兵的生命值第一次小于等于据点攻击力的位置,从而使该据点的杀敌数加一。
代码
#include <iostream> #include <cstring> #include <algorithm> using namespace std; int h[1000000],w[1000000],cont[1000000]; int main() { ios::sync_with_stdio(false); int n,m,i; while(cin>>n>>m) { memset(cont,0,sizeof(cont)); for(i=0;i<m;i++) cin>>h[i]; for(i=0;i<n;i++) { cin>>w[i]; if(i!=0) w[i]+=w[i-1]; } for(i=0;i<m;i++) { int x=lower_bound(w,w+n,h[i])-w; cont[x]++; } for(i=0;i<m;i++) cout<<cont[i]<<endl; } return 0; }