SMU Summer 2024 Contest Round 1

[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;
}

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值