[ABC127E] Cell Distance - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
思路:本场最有价值的题目。解法如代码注释:
看了洛谷的第一篇题解,如雷贯耳!还是要一步一步斟酌,不然再次遇到类似的题,连第一步都想不到.
思路:分别考虑x坐标和y坐标对答案的贡献!
对于行与行之间的差值d. d的取值区间为[0,n-1]!
d=0时,共有(x1,x1),(x2,x2)...(xn,xn).共n对
d=1时,共有(x1,x2),(x2,x3)...(xn-1,xn).共n-1对
以此类推,可以发现对应不同对d,会有n-d对这样的x组合;而对于y坐标,则有m*m种组合
那么x坐标的贡献Vx=(d=[0,n-1])∑(d*(n-d)*m*m).
同理可得,Vy=(d=[0,m-1])∑(d*(m-d)*n*n).
那么总贡献为ans=(Vx+Vy)*C(n*m-2,k-2).
其中组合数C(n*m-2,k-2)为从n*m中已经选了一对(x1,y1),(x2,y2)之后,在剩下的n*m-2个格子中选择k-2个的组合数
还有一个问题是怎么更快的算组合数? k<=n*m<=2e5--逆元求组合数o(n)
const int mod=1000000007;
int n,m,k;
int getVx(){
int sum=0;
for(int i=0;i<=n-1;i++) (sum+=i*(n-i)*m*m)%=mod;
return sum;
}
int getVy(){
int sum=0;
for(int i=0;i<=m-1;i++) (sum+=i*(m-i)*n*n)%=mod;
return sum;
}
int quickpow(int a,int b){
int res=1;
while(b){
if(b&1) (res*=a)%=mod;
(a*=a)%=mod;
b>>=1;
}
return res;
}
int getC(int x,int y){ 逆元求组合数o(n);在x中选y个
int fz=1,fm=1;
for(int i=x;i>=x-y+1;i--) (fz*=i)%=mod;
for(int i=y;i>=1;i--) (fm*=i)%=mod;
求fm的逆元:quickpow(fm,mod-2).逆元可以解决分数无法取模的问题
return (fz*quickpow(fm,mod-2))%mod;
}
看了洛谷的第一篇题解,如雷贯耳!还是要一步一步斟酌,不然再次遇到类似的题,连第一步都想不到.
思路:分别考虑x坐标和y坐标对答案的贡献!
对于行与行之间的差值d. d的取值区间为[0,n-1]!
d=0时,共有(x1,x1),(x2,x2)...(xn,xn).共n对
d=1时,共有(x1,x2),(x2,x3)...(xn-1,xn).共n-1对
以此类推,可以发现对应不同对d,会有n-d对这样的x组合,而对于y坐标,则有m*m种组合
那么x坐标的贡献Vx=(d=[0,n-1])∑(d*(n-d)*m*m)
同理可得,Vy=(d=[0,m-1])∑(d*(m-d)*n*n)
那么总贡献为ans=(Vx+Vy)*C(n*m-2,k-2);
其中组合数C(n*m-2,k-2)为从n*m中已经选了一对(x1,y1),(x2,y2)之后,在剩下的n*m-2个格子中选择k-2个的组合数
还有一个问题是怎么更快的算组合数? k<=n*m<=2e5--逆元求组合数o(n)
[ABC127E] Cell Distance
https://www.luogu.com.cn/problem/AT_abc127_e
void solve(){ 补D 求所有方案数的权值 之和---无从下手;
cin>>n>>m>>k;
int Vx=getVx(),Vy=getVy();
cout<<((Vx+Vy)%mod)*getC(n*m-2,k-2)%mod;
}
C(n*m,k) 并且C(k,2)..无从下手。。
补完之后感觉很nb的一个题
[ABC131E] Friendships - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
思路:本题为构造题。往怎么构造可以达到最大d=2的对数方面想.
需要想到构造的图是一个菊花图,因为此时可以达到最大满足d=2的对数有(n-2)*(1+n-2)/2
如果k大于最大可能值,那么输出-1。
如果等于,则直接输出图。如果小于则可以给花瓣直接建边。这样可以一直把满足条件的对数降到0
所以可能值的区间为[0,(n-2)*(1+n-2)/2].k在区间内才有答案.
思路:构造一个菊花图,此时可以达到最大满足d=2的对数有(n-2)*(1+n-2)/2
如果k大于最大可能值,那么输出-1。
如果等于,则直接输出图。如果小于则可以给花瓣直接建边。这样可以一直把满足条件的对数降到0
所以可能值的区间为[0,(n-2)*(1+n-2)/2].k在区间内才有答案.
[ABC131E] Friendships
https://www.luogu.com.cn/problem/AT_abc131_e
void solve(){ 补E 构造--能想到菊花图就不难了.但是样例给的比较歪,不一定能想到。
int n,k; cin>>n>>k;
int maxn=(n-2)*(1+n-2)/2;
if(k>=0&&k<=maxn){
int m=n-1; 初始菊花图需要的边数
int dif=maxn-k; 需要降低的值
m+=dif;
cout<<m<<endl;
for(int i=1;i<n;i++) cout<<i<<" "<<n<<endl; 菊花图
int cur=1,next=2;
while(dif--){
cout<<cur<<" "<<next<<endl;
if(next==n-1) cur++,next=cur+1;
else next++;
}
}
else cout<<"-1";
}
[ABC134E] Sequence Decomposing - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
思路:简单题。二分+贪心。二分答案,数字贪心地跟在比他小的数字中最大的那个的后面。
int n;
int arr[200005];
bool check(int x){
multiset<int> mst;
for(int i=1;i<=n;i++){
if(mst.size()==0) mst.insert(arr[i]);
else{
auto p=mst.lower_bound(arr[i]);
if(p!=mst.begin()){
mst.erase(prev(p));
mst.insert(arr[i]);
}
else if(mst.size()<x) mst.insert(arr[i]);
else return false;
}
}
return true;
}
void solve(){
cin>>n;
for(int i=1;i<=n;i++) cin>>arr[i];
int ans=n;
int l=1,r=n;
while(l<=r){
int mid=(l+r)>>1;
if(check(mid)){
ans=mid;
r=mid-1;
}
else l=mid+1;
}
cout<<ans;
}
[ABC127D] Integer Cards - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
思路:因为留下的卡牌数目是固定的,那么肯定是留下最大的那一些。那么可以对原有的卡牌和用作替换的卡牌从小到大排列。贪心地取即可。当可以替换的牌比当前牌要大,那么就替换。时间复杂度o(n+m)
int n,m;
int arr1[100005];
pair<int,int> arr2[100005];
void solve(){
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>arr1[i];
sort(arr1+1,arr1+n+1);
for(int i=1;i<=m;i++) cin>>arr2[i].second>>arr2[i].first;
sort(arr2+1,arr2+m+1);
int idx=1;
for(int j=m;j>=1;j--){
int b=arr2[j].second,c=arr2[j].first;
while(idx<=n&&b--&&c>arr1[idx]){
arr1[idx]=c;
idx++;
}
if(idx>n||c<=arr1[idx]) break;
}
int ans=0;
for(int i=1;i<=n;i++) ans+=arr1[i];
cout<<ans;
}