题目链接:http://codeforces.com/contest/1077
A.Frog Jumping
解题思路:作差再判断最后是否还要向右跳一次即可。
AC代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 LL T,a,b,k; 5 int main(){ 6 while(cin>>T){ 7 while(T--){ 8 cin>>a>>b>>k; 9 cout<<(a-b)*(k/2)+(k%2?a:0)<<endl; 10 } 11 } 12 return 0; 13 }
B.Disturbed People
解题思路:题意已说得很清楚了,只要找到满足a[i-1]==1&&a[i]==0&&a[i+1]==1,那么就关掉第i-1和第i+1间房间的灯(其状态值改为0),若满足条件--->i+=3,表示当前的灯已熄灭,只需站到第i+3间房间继续检查即可。
AC代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 int n,cnt,a[105]; 5 int main(){ 6 while(cin>>n){ 7 cnt=0; 8 for(int i=0;i<n;++i)cin>>a[i]; 9 for(int i=1;i<n-1;){ 10 if(a[i-1]&&!a[i]&&a[i+1])cnt++,i+=3; 11 else i++; 12 } 13 cout<<cnt<<endl; 14 } 15 return 0; 16 }
C.Good Array
解题思路:统计所有元素之和:sum,然后枚举每个元素,令tmp=(sum-a[i])>>1表示原数组删去a[i]后剩余元素之和的一半,由"好的数组"定义可知,如果(sum-a[i])为奇数,则剩下的元素肯定不能分成相等的两部分;否则只需检查tmp是否在剩下的元素当中,若是则归纳答案!
AC代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 const int maxn=2e5+5; 5 int n,k,b[maxn];LL a[maxn],sum,tmp;map<LL,int> mp; 6 int main(){ 7 while(~scanf("%d",&n)){ 8 sum=0,k=0;mp.clear(); 9 for(int i=1;i<=n;++i)scanf("%lld",&a[i]),sum+=a[i],mp[a[i]]++;///要用map或一维数组记录每个数字出现的次数,不能用set容器 10 for(int i=1;i<=n;++i){ 11 if((sum-a[i])&1LL)continue;///奇数则跳过 12 tmp=(sum-a[i])>>1; 13 mp[a[i]]--;///先删去该元素 14 if(mp[tmp])b[k++]=i; 15 mp[a[i]]++;///再添加该元素 16 } 17 printf("%d\n",k); 18 if(!k)puts(""); 19 for(int i=0;i<k;++i)printf("%d%c",b[i],(i==k-1)?'\n':' '); 20 } 21 return 0; 22 }
D.Cutting Out
解题思路:题目要求找出k个元素组成的集合t,使得每次删去集合s中包含t集合中的k个元素,并且最大化删除的次数,典型的二分查找答案!先统计每个元素出现的次数cnt_i,再通过二分查找最大化删除的次数z,二分条件为∑cnt_i/z≥k,如果为True,则向右找更大的删除次数,否则向左找较小的删除次数,最后每个元素被挑选的个数就为cnt_i/z',简单输出集合t中的k个元素即可。
AC代码:
1 #include<iostream> 2 #include<cstdio> 3 #include <map> 4 #include <vector> 5 using namespace std; 6 typedef long long LL; 7 int n, k, x, l, r, mid, t; 8 map<int, int> mp; 9 vector<int> ans, cnt; 10 bool check(int z){ 11 int sum = 0; 12 for (auto num : cnt)sum += num / z; 13 return sum >= k; 14 } 15 int main(){ 16 while (~scanf("%d%d", &n, &k)){ 17 mp.clear(), ans.clear(), cnt.clear(); l = 1, r = n; 18 for (int i = 0; i < n; ++i)scanf("%d", &x), mp[x]++; 19 for (auto y : mp)cnt.push_back(y.second);///保存对应数字出现的次数 20 while (l <= r){///二分查找要切的最大次数 21 mid = (l + r) >> 1; 22 if (check(mid))l = mid + 1;///最大化往右边找 23 else r = mid - 1; 24 } 25 for (auto u : mp){ 26 t = u.second / r; 27 while (t--)ans.push_back(u.first);///第i个元素一次需要取t个 28 } 29 for (int i = 0; i < k; ++i)printf("%d%c", ans[i], i == k - 1 ? '\n' : ' '); 30 } 31 return 0; 32 }