标签:10 连边 颜色 Min int 题解 Teams MAXN Selecting
\(Description:\)
给一个序列,每个数有一个颜色c,权值w,不同颜色的若w和小于等于B可交换,相同颜色若w和小于等于A可交换,求最后的序列可能的个数,对1e9+7取模。(相同颜色不同权值算同一种)
\(Sample\) \(Input\):
4 7 3
3 2
4 3
2 1
4 4
\(Sample\) \(Output\):
2
简化一下题目,发现其实是先求出最大联通块的大小,设这个联通块大小为s,颜色相同的点的个数为x,那么答案就是\(A_{s}^{s-x}\),A是排列数,那么考虑怎么求出最大联通块的大小,可以计每个颜色的最小权值,在计一个全局最小权值,如果全局最小可以和颜色最小连边,就连边。
一开始先处理出每个颜色的可以和该颜色最小值连边的所有点,更新这个颜色的联通块大小。
但要注意,如果该颜色是全局最小值的颜色的话,不能直接跟全局最小值加起来比较,还要考虑,他和其他次小元素的和是否可以跨颜色连边。
然后把所有最小值尝试和全局最小值连边,更新s。
在更新答案,(注意逆元问题)
然后就差不多结束了^_^
#include<cstdio>
#include<cstring>
#include<iostream>
#include<vector>
#define int long long
using namespace std;
int n,m,cnt,Min_all,A,B,ans,ss,num;
const int MAXN=1e6;
const int OO=0x3f3f3f3f;
const int p=1e9+7;
int size[MAXN+10];
int c[MAXN+10],w[MAXN+10];
vector <int> v[MAXN+10];
int fac[MAXN+10],inv[MAXN+10];
int bac[MAXN+10],Min[MAXN+10];
int _bac[MAXN+10];
inline int Inv(int a,int b,int p){
int ret=1;
for(;b;a=(a*a)%p,b>>=1)if(b&1)ret=(ret*a)%p;
return ret;
}
signed main(){
if(fopen("keep.in","r")){
freopen("keep.in","r",stdin);
freopen("keep.out","w",stdout);
}
scanf("%lld%lld%lld",&n,&A,&B);
for(int i=1;i<=n;++i)Min[i]=i;
fac[0]=fac[1]=1;
for(int i=2;i<=n;++i)fac[i]=(fac[i-1]*i)%p;
inv[n]=Inv(fac[n],p-2,p)%p;
inv[0]=inv[1]=1;
for(int i=n-1;i>=2;--i)inv[i]=(inv[i+1]*(i+1))%p;
for(int i=1;i<=n;++i)scanf("%lld%lld",&c[i],&w[i]);
for(int i=1;i<=n;++i){
if(!bac[c[i]])bac[c[i]]=++cnt,_bac[cnt]=c[i];
v[bac[c[i]]].push_back(i);
}
for(int i=1;i<=cnt;++i)for(int j=0;j<(int)v[i].size();++j){
if(j==0)Min[i]=v[i][j];
else
Min[i]=(w[Min[i]]>w[v[i][j]])?v[i][j]:Min[i];
}
for(int i=1;i<=cnt;++i)size[Min[i]]=(int)v[i].size();
Min_all=Min[1];
for(int i=2;i<=cnt;++i)
Min_all=(w[Min_all]>w[Min[i]])?Min[i]:Min_all;
ss=OO;
for(int i=1;i<=cnt;++i){
if(Min_all==Min[i])continue;
ss=min(ss,w[Min[i]]);
}
for(int i=1;i<=cnt;++i)for(int j=0;j<(int)v[i].size();++j){
if(Min[i]!=v[i][j] && w[Min[i]]+w[v[i][j]]<=A)continue;
if(c[Min_all]!=_bac[i] && w[v[i][j]]+w[Min_all]<=B)continue;
if(c[Min_all]==_bac[i] && w[v[i][j]]+ss<=B)continue;
size[Min[i]]--;
}
num=size[Min_all];
for(int i=1;i<=cnt;++i){
if(Min_all==Min[i])continue;
if(w[Min[i]]+w[Min_all]<=B)
num+=size[Min[i]];
}
ans=1;
for(int i=1;i<=cnt;++i){
if(w[Min[i]]+w[Min_all]<=B || Min_all==Min[i])
ans=(ans*inv[size[Min[i]]])%p;
}
ans=(ans*fac[num])%p;
printf("%lld\n",ans);
return 0;
}
标签:10,连边,颜色,Min,int,题解,Teams,MAXN,Selecting 来源: https://www.cnblogs.com/JCNL666/p/10634986.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。