前缀和,枚举+递推(Average,HDU 5353)
来源:互联网 发布:淘宝全新店铺购买 编辑:程序博客网 时间:2024/05/18 01:20
有n个节点,1<=n<=1e5,成环,每个节点有一些物品,相邻节点可以传递一次物品,1和n相邻。
瞬间就想起了
Money Transfers
这类问题一般都可以转化为环的切割,如何求出切割呢?
可以求一个前缀和,如果sum[j]==sum[i](i<j)那么[i+1,j]就可以切割成一段,首尾剩下的也可以并成一段。
我们会找到很多个sum的值,每一种值对应一个切割方法,值所对应的的多个节点就都是切割点。
在本题我们就通过前缀和找到所有切割,然后对于每一段,可以直接贪心模拟看看是否ok。
看了下官方题解,是枚举第一个人的操作,然后递推出其他人的操作。
因为环状的问题要同时兼顾两边,所以没有什么简单的算法可以得到答案。
但是如果能在环上切一刀,那么问题就变成了一个线段上的问题,这个时候问题会大大化简,我们甚至可以直接贪心递推来得到答案。
即枚举+递推。
本题代码
#include<stdio.h>#include<map>#include<vector>#include<algorithm>using namespace std;typedef long long ll;const int maxn = 100010;int n;int a[maxn<<1];int sum[maxn];ll SUM;map<int,int>MAP;int cnt;vector<int>vec[maxn];vector<int>ans;void read(){ MAP.clear(); cnt=0; SUM=0; scanf("%d",&n); for(int i=0;i<n;i++) { scanf("%d",a+i); SUM+=a[i]; }}int id(int x){ if(!MAP.count(x)) { MAP[x]=++cnt; vec[cnt].clear(); } return MAP[x];}bool OK(int l,int r){ if(r-l<=1) return true; int jin=0; for(int k=l+1;k<=r;k++) { int x = a[k]+jin; if(x>=2||x<=-2) return false; if(x==1) { ans.push_back(k); ans.push_back(k+1); } else if(x==-1) { ans.push_back(k+1); ans.push_back(k); } jin=x; } return !jin;}bool ok(int x){ ans.clear(); for(int i=0;i<(int)vec[x].size()-1;i++) if(!OK(vec[x][i],vec[x][i+1])) return false; if(!OK(vec[x][(int)vec[x].size()-1],vec[x][0]+n)) return false; return true;}void print(){ puts("YES"); printf("%d\n",ans.size()/2); for(int i=0;i<(int)ans.size();i+=2) printf("%d %d\n",ans[i]%n+1,ans[i+1]%n+1);}int solve(){ read(); if(SUM%n) return 0*puts("NO"); SUM/=n; for(int i=0;i<n;i++) { a[i]-=SUM; if(a[i]>2||a[i]<-2) return 0*puts("NO"); a[i+n]=a[i]; sum[i]=a[i]; if(i) sum[i]+=sum[i-1]; } for(int i=0;i<n;i++) vec[id(sum[i])].push_back(i); for(int i=1;i<=cnt;i++) if(ok(i)) { print(); return 0; } puts("NO"); return 0;}int main(){ int T; scanf("%d",&T); while(T--) solve(); return 0;}
Money Transfers代码
#include<stdio.h>#include<algorithm>#include<map>using namespace std;typedef long long ll;const int maxn = 100010;int n;ll sum[maxn];map<ll,int>cnt;int main(){ scanf("%d",&n); for(int i=0;i<n;i++) scanf("%lld",sum+i); for(int i=1;i<n;i++) sum[i]+=sum[i-1]; for(int i=0;i<n;i++) cnt[sum[i]]++; int MAX=0; for(map<ll,int>::iterator it = cnt.begin();it!=cnt.end();++it) MAX=max(MAX,it->second); printf("%d\n",n-MAX); return 0;}
阅读全文
0 0
- 前缀和,枚举+递推(Average,HDU 5353)
- HDU 5353 Average(枚举)
- hdu 5163 前缀和+枚举
- HDU 5965 扫雷(递推+枚举)
- HDU 5965 扫雷 (递推+枚举)
- HDU-4476 Cut the rope (枚举、前缀和)
- HDU 5353 Average(破解环的做法是枚举起始点の操作,灵活题)
- hdu 5353 Average(暴力)
- HDU 5353 Average(贪心)
- 前缀和(推一下公式)
- 枚举+前缀和...
- hdoj Average 5353 (递推&&数学情况考虑) 好题
- hdu 5353 Average(贪心+构造)
- HDU 5353 Average
- HDU 5353 Average
- HDU 5353 Average
- HDU 5353 Average 贪心
- [Bzoj 1177][Apio2009] Oil 前缀和+递推
- Codeforces Round #423 (Div. 2)A Restaurant Tables 思维题
- Ambari Server安装失败解决
- Leetcode#371. Sum of Two Integers (位运算实现加法)
- segmentProject-summer
- 图像分割—基于图的图像分割(Graph-Based Image Segmentation)
- 前缀和,枚举+递推(Average,HDU 5353)
- Q120:PBRT-V3,“直接光照”积分器(14.3章节)
- Intellij IDEA基于Springboot的远程调试
- Guava Table接口
- nginx问题知识汇总
- 怎么申请苹果iOS开发者账号?ios开发者账号申请流程介绍
- Spring_02_Bean基本配置
- python3 网络爬虫(四)如何查找以及使用cookies
- 详解java动态代理模式