codeforces 628F
2016-03-19 12:07
239 查看
原题
原题链接题目大意
给你一个集合的大小NN,NN是55的倍数。然后有一些限制:
集合里的数范围是[1,b][1,b].
集合中的数mod5=0,1,2,3,4mod 5=0,1,2,3,4的数的个数各为N/5N/5。
还有qq个附加限制,就是元素值为[1,upToi][1,upTo_i]的个数为quantityiquantity_i。
问是否存在一个集合满足条件。
范围
(5 ≤ n ≤ b ≤ 104,1 ≤ q ≤ 104)(5 ≤ n ≤ b ≤ 10^4, 1 ≤ q ≤ 10^4)解题思路
我们不妨加一个限制就是元素值为[1,b][1,b]的个数为nn。这样,我们的限制就可以描述集合了。先按限制的upToupTo排序,对于限制ii以及限制i−1i-1,在upToi−1upTo_{i-1}到upToiupTo_i之间增加的数的个数就是quantityi−quantityi−1quantity_i-quantity_{i-1},而且在这个区间中,增加的数对5取模的个数也是可以算出来的。然后就可以使用网络流了,(S,mod0,n/5)(S,mod0,n / 5),(S,mod1,n/5)(S,mod1,n / 5),(S,mod2,n/5)(S,mod2,n / 5),(S,mod3,n/5)(S,mod3,n / 5),(S,mod4,n/5)(S,mod4,n / 5),表示modmod不同值的个数都是n/5n / 5,(i,T,quantityi−quantityi−1)(i,T,quantity_i-quantity_{i-1}),还有就是把每个区间的对5取模的个数求出来连边就行了。
参考程序
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define fo(i,a,b) for(int i=a;i<=b;i++) #define fd(i,a,b) for(int i=a;i>=b;i--) #define maxn 10055 #define cannot() puts("unfair") #define can() puts("fair") #define oo 1e9 using namespace std; int n,b,q,S,T; int head[maxn],t[maxn*20],next[maxn*20],v[maxn*20],sum; int tmp[10]; struct note{ int up,num; }a[maxn]; bool cmp(note i,note j){ return i.up<j.up||i.up==j.up && i.num<j.num; } void ins(int x,int y,int z){ t[++sum]=y; v[sum]=z; next[sum]=head[x]; head[x]=sum; } void insert(int x,int y,int z){ ins(x,y,z); ins(y,x,0); } int vh[maxn],dis[maxn],di[maxn],his[maxn],pre[maxn],ans; void sap(){ int tp=T; bool p; vh[0]=tp+1; int x=S; int aug=oo; while (dis[S]<tp){ p=0; his[x]=aug; for(int i=di[x];i;i=next[i]){ if (v[i]&&dis[t[i]]+1==dis[x]){ p=1; di[x]=i; pre[t[i]]=x; aug=min(aug,v[i]); x=t[i]; if (x==T){ ans+=aug; while (x!=S){ int tmp=x; x=pre[x]; v[di[x]]-=aug; v[di[x] ^ 1]+=aug; } aug=oo; } break; } } if (!p){ int k,min; min=tp+1; for(int i=head[x];i;i=next[i]){ if (v[i]&&min>dis[t[i]]){ min=dis[t[i]]; k=i; } } --vh[dis[x]]; if (vh[dis[x]]==0) break; vh[++min]++; dis[x]=min; di[x]=k; if (x!=S){ x=pre[x]; aug=his[x]; } } } } int main(){ sum=1; scanf("%d%d%d",&n,&b,&q); fo(i,1,q) scanf("%d%d",&a[i].up,&a[i].num); a[++q].up=b; a[q].num=n; sort(a+1,a+q+1,cmp); fo(i,2,q){ if (a[i].up==a[i-1].up&&a[i].num!=a[i-1].num){ cannot(); return 0; } if (a[i].up>a[i-1].up&&a[i].num<a[i-1].num){ cannot(); return 0; } } S=0; T=q+1; fo(i,1,q){ if (i>1) tmp[0]=a[i].num-a[i-1].num; else tmp[0]=a[i].num; int down; if (i>1) down=a[i-1].up; else down=0; insert(S,i,tmp[0]); fo(j,0,4) tmp[j]=a[i].up / 5; fo(j,0,a[i].up % 5) tmp[j]++; fo(j,0,4) tmp[j]-=down/5; fo(j,0,down % 5) tmp[j]--; fo(j,0,4) insert(i,T+j,tmp[j]); } fo(i,0,4) insert(T+i,T+5,n / 5); T+=5; sap(); if (ans==n) can(); else cannot(); return 0; }
相关文章推荐
- C# 在第二个窗体上添加数据之后如何刷新第一个窗体加载的数据
- 商业研究(7):旅游市场概览
- 第三次作业 (一)----------------------Visual Studio 2015的安装及单元测试
- 【蓝桥杯】根据给定的手机尾号(4位),按照一定的规则来打分
- NYOJ+dp+使用三维数组来记忆
- cmd
- Android Studio相关资料链接
- poj 2502 Subway
- OSI 七层模型与各层设备对应 详细解释<TCP/IP下数据是如何进行传输>
- 射线与三角面
- 5 个顶级 Android 开源库
- 网络编程学习总结
- 常用插件
- 深入解析JavaScript中函数的Currying柯里化
- UItableView创建
- 射线与平面
- c++ move semantics
- 欢迎使用CSDN-markdown编辑器
- hihocoder 第八十九周
- 计算落入一定高程范围的各土地类型面积