[NOIP2017模拟][bzoj4264]小c找朋友
2017-10-16 22:53
197 查看
题目背景
bzoj4264⇐这是一道权限题
题目描述
给定一张无向图,求满足以下条件的点对 (x,y) 数目:对任意点 z (z!=x,y),边 (x,z) 和 (y,z) 同时存在或同时不存在。
输入格式
一行两个整数 n,m ,分别表示这幅图点数和边的数量。
接下来 m 行,每行两个整数,表示这两个点之间存在一条无向边。保证没有重边和自环。
输出格式
输出一行一个整数,表示答案。
样例数据
输入
3 3
1 2
2 3
1 3
输出
3
备注
【数据范围】
对于前 30% 的数据:n,m<=500;
对于 100% 的数据:n,m<=106。
分析:这道题我思考了很久,也打了很久,觉得能AC,结果只有10分。思路是这样的:给每个点一个随机值,连每一条边的时候每个点有一个数组加上对面点的随机值,也就意味着如果两个点所连的点集是完全相同的,这个数组中对应的和就应该相同(由于存编号很容易和相同,比如说2、3和1、4分别连接了两个点,编号和是一样的,就判错了,所以要随机值)。对于那些之间有边的满足条件的点对,因为加了对方的随机值,所以数组中的和不一样,我们就枚举每一条边,把两边的点减去对面点的随机值,如果此时数组中的和一样了,说明是满足条件的;对于那些之间没有边的满足条件的点对,就直接判断数组中的和是否相同就行了。
为什么错了呢?因为我用了hash表(我开始怀疑我的板子有问题了orz)而且只随机了一次。
而正解,用的离散化而且随机了三次以上……
P.S. 如果你离散化了四次还WA点,那你的霉运都用在做错这道题上了,劝你去买彩票吧……
如果你离散化一次就AC的话,那你的好运全用在做对这道题上了,劝你一辈子都别买彩票……
代码
本题结。
bzoj4264⇐这是一道权限题
题目描述
给定一张无向图,求满足以下条件的点对 (x,y) 数目:对任意点 z (z!=x,y),边 (x,z) 和 (y,z) 同时存在或同时不存在。
输入格式
一行两个整数 n,m ,分别表示这幅图点数和边的数量。
接下来 m 行,每行两个整数,表示这两个点之间存在一条无向边。保证没有重边和自环。
输出格式
输出一行一个整数,表示答案。
样例数据
输入
3 3
1 2
2 3
1 3
输出
3
备注
【数据范围】
对于前 30% 的数据:n,m<=500;
对于 100% 的数据:n,m<=106。
分析:这道题我思考了很久,也打了很久,觉得能AC,结果只有10分。思路是这样的:给每个点一个随机值,连每一条边的时候每个点有一个数组加上对面点的随机值,也就意味着如果两个点所连的点集是完全相同的,这个数组中对应的和就应该相同(由于存编号很容易和相同,比如说2、3和1、4分别连接了两个点,编号和是一样的,就判错了,所以要随机值)。对于那些之间有边的满足条件的点对,因为加了对方的随机值,所以数组中的和不一样,我们就枚举每一条边,把两边的点减去对面点的随机值,如果此时数组中的和一样了,说明是满足条件的;对于那些之间没有边的满足条件的点对,就直接判断数组中的和是否相同就行了。
为什么错了呢?因为我用了hash表(我开始怀疑我的板子有问题了orz)而且只随机了一次。
而正解,用的离散化而且随机了三次以上……
P.S. 如果你离散化了四次还WA点,那你的霉运都用在做错这道题上了,劝你去买彩票吧……
如果你离散化一次就AC的话,那你的好运全用在做对这道题上了,劝你一辈子都别买彩票……
代码
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<ctime> #include<cmath> #include<algorithm> #include<cctype> #include<iomanip> #include<queue> #include<set> using namespace std; int getint() { int sum=0,f=1; char ch; for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar()); if(ch=='-') { f=-1; ch=getchar(); } for(;isdigit(ch);ch=getchar()) sum=(sum<<3)+(sum<<1)+ch-48; return sum*f; } const int maxn=1000010; struct node{ int x,y; }bian[maxn]; struct node2{ long long c,tot; }index[maxn+111317]; int n,m,x,y,cnt,maxx=111317; int num[maxn]; long long ans,w[maxn],wtot[maxn]; int main() { //freopen("graph.in","r",stdin); //freopen("graph.out","w",stdout); srand(time(0)); n=getint(),m=getint(); for(int i=1;i<=m;++i) { x=getint(),y=getint(); if(!w[x])//给每个点一个随机值 w[x]=(rand()%1000)*(rand()%1000)*(rand()%1000);//我是直接rand()%1000000000,而正解三个(及以上)小随机数连乘,更加随机 if(!w[y]) w[y]=(rand()%1000)*(rand()%1000)*(rand()%1000); bian[++cnt].x=x,bian[cnt].y=y;//记录边,用来枚举有边相连的满足条件的点对 num[y]++;//我还记录了一下每个点连了多少边,这样边数相同、和相同双保险 wtot[y]+=w[x];//数组加上随机值 num[x]++; wtot[x]+=w[y]; } for(int i=1;i<=m;++i)//枚举有边相连的满足条件的点对 { x=bian[i].x,y=bian[i].y; if(num[x]==num[y])//保险1 { wtot[x]-=w[y]; wtot[y]-=w[x]; if(wtot[x]==wtot[y])//保险2 ans++; wtot[x]+=w[y]; wtot[y]+=w[x]; } } sort(wtot+1,wtot+n+1);//离散化(好吧,其实就是排个序) for(int i=1;i<=n;i++)//记录每一种和相同的有多少个,之后用排列组合加给ans(这里没有双保险,因为这是我在我的hash代码的基础上改的,这部分离散化是加的) { int r=i; while(wtot[r+1]==wtot[r])r++;//和相同就r一直右移 ans+=(long long)(r-i)*(r-i+1)/2;//r-i就算出了和为wtot[i]的有多少个,排列组合 i=r; } cout<<ans<<'\n'; return 0; }
本题结。
相关文章推荐
- [NOIP模拟][BZOJ4264]小c找朋友
- [NOIP2017模拟][SCOI2005][bzoj1084]最大子矩阵
- 5334. 【NOIP2017提高A组模拟8.24】空
- JZOJ 5197. 【NOIP2017提高组模拟7.3】C
- 【jzoj5344】【NOIP2017模拟9.3A组】【摘果子】【树型依赖背包】
- JZOJ5379. 【NOIP2017提高A组模拟9.21】Victor爱数字
- [JZOJ5442]【NOIP2017提高A组冲刺11.1】荒诞([BZOJ3060]【POI2012】Tour de Byteotia)
- [NOIP2017模拟]hello
- [NOIP2017模拟]弹球
- [NOIP2017模拟]电影
- JZOJ5390. 【NOIP2017提高A组模拟9.26】逗气 单调队列
- JZOJ 100035. 【NOIP2017提高A组模拟7.10】区间
- JZOJ 100045. 【NOIP2017提高A组模拟7.13】好数
- JZOJ100045. 【NOIP2017提高A组模拟7.13】好数
- [NOIP2017模拟]路径统计
- [NOIP2017模拟]Sequence
- jzoj5399 【NOIP2017提高A组模拟10.7】Confess
- JZOJ5400. 【NOIP2017提高A组模拟10.7】Repulsed 树型DP+贪心
- [NOIP2017模拟]Fibonacci
- 【JZOJ5287】【NOIP2017提高A组模拟8.16】最短路