2016 ICPC EC-Final(China-Final)(F待补)

A. Number Theory Problem

题意:求2n以内2k-1有多少个7的倍数。

思路:签到题。一开始呢,看到这个就想直接除3。但是还是不太敢。最后发现就是除3就完了。如果考虑直接n个2乘起来,那肯定会爆long long,所以需要一边乘一边取模。然后可以发现,8对7取模,是1,那么8*8对7取模,还是等于 1。所以x个8相乘,就是23x对7取模是1,那么23x-1正好,模7 就是0了。所以 直接n/3就是答案了。

AC代码:

#include <bits/stdc++.h>
#define int long long
#define mk make_pair
using namespace std;
const int N = 1e6+7;
const int mod = 1e9+7;
int t,n,m,k;
int a[N];
int sum[N];


signed main(){
    int t = 1,cas = 1;
    scanf("%lld",&t);
    while(t-- ){
        scanf("%lld",&n);
        printf("Case #%lld: %lld\n",cas++,n/3);
    }
    return 0;
}

D. Ice Cream Tower

题意:一个商店,有n个冰激凌球,每个球有一定的宽度。 然后现在要堆成x个高度为k的冰激凌塔。要求,下一层的冰激凌必须大于等于上一层的两倍,才能叠在一起。问最多能做多少个高度为k的冰激凌。

思路:还是挺好想的。二分答案。对于一个枚举的x值,贪心的求解,当然要先排序。要做成x个冰激凌,那么最底下一层,肯定是最大的x个球。然后遍历后面的球,因为是从大到小排序的,肯定是大的能放先放大的,第二层的pos位置放掉了,自然下一个就放pos+1位置。如果这一层就放完了,就下一层从头开始,就这样一层一层叠上去就好了。然后检查层数是否大于x。check的过程是O(n)的,二分是O(log n)的。时间可以接受。这题时间给的也非常友好 6s。代码跑了 1.5s。

AC代码:

#include <bits/stdc++.h>
#define int long long
#define mk make_pair
using namespace std;
const int N = 3e5+11;
const int mod = 1e9+7;
int t,n,m,k;
int a[N];
int selected[N];
 
bool check(int x){
    int pos = 0;
    for(int i = 0 ; i < x ; i ++)
        selected[i] = a[i];
    //for(int j = 0 ; j < x ; j ++)printf("%lld ",selected[j]);printf("\n");
    int cnt = 1;
    for(int i = x ; i < n ; i ++){
        if(a[i]*2 <= selected[pos]){
            selected[pos] = a[i];
            pos ++;
            if(pos == x){
                //for(int j = 0 ; j < x ; j ++)printf("%lld ",selected[j]);printf("\n");
                pos = 0;
                cnt ++;
            }
        }
    }
    return cnt >= k;
}
 
 
signed main(){
    int t = 1,cas = 1;
    scanf("%lld",&t);
    int tt = t;
    while(t-- ){
        scanf("%lld%lld",&n,&k);
        for(int i = 0 ; i < n ; i ++) scanf("%lld",&a[i]);
        sort(a,a+n,greater<int>() );
        int l = 1;
        int r = n/k;
        int res =  0;
        while(l <= r ){
            int mid = (l+r)>>1;
            //cout<<mid<<endl;
            if(check(mid)){
                res = max(mid,res);
                l = mid+1;
            }else{
                r = mid-1;
            }
        }
        printf("Case #%lld: %lld\n",cas++,res);
    }
    return 0;
}

E. Bet

题意:n个队伍比赛,现在要下注。每个队伍都有对应的赔率。输了就没钱,赢了就能获得 本钱+赔率*本钱。现在要求,在压的x个队伍中,只要任意一个队伍获胜,就能赢钱(比本钱还多就赢钱了)的条件下,最多可以压多少个队伍。

思路:一开始想歪了。结果弄来弄去始终没有回到正确的道路上。首先假设本钱就1块钱。然后拿去下注。对于任意一个队伍。求,如果想赢回1块钱,最少需要压多少钱。然后每个都求完了。排个序,从需要的钱小的开始压。直到本钱大于等于1块钱收手。因为这些队伍都是计算过,只要赢了就能回1块多的。而他们加起来的本钱又少于等于1,所以显然是符合要求的。这题的坑点在于卡精度。要用long double。

AC代码:

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e6+7;
const int mod = 1e9+7;
int t,n,m,k;
long double a[N],b[N];
long double one = 1.0;

signed main(){
    int t;
    cin>>t;
    for(int cas = 1 ; cas <= t ; cas ++){
        cin>>n;
        for(int i = 0 ; i < n ; i ++){
            long double x,y;
            char buf;
            cin>>x>>buf>>y;
            a[i] = 1.0/(1.0+y/x);
        }
        sort(a,a+n);
        long double sum = 0;
        int res = 0;
        for(int i = 0 ; i < n ; i ++){
            if(sum+a[i] < 1.0){
                sum += a[i];
                res ++;
            }
        }
        cout<<"Case #"<<cas<<": "<<res<<endl;
    }

    return 0;
}

H. Great Cells

题意:给定一个n*m的网格。然后往里面填数字。如果一个点是该行和该列的严格的最大值,那么他就是一个 Great Cell。现在要求。网格中有 0和g点,1个g点, … , n*m个g点的所有的方案数加权求和是多少。

在这里插入图片描述

思路:推导过程参考了博客,比较详细的推导过程:https://www.cnblogs.com/qieqiemin/p/14074611.html

推到第三行,可以发现右半部分,其实就是所有的情况。然后左半部分,是枚举所有点作为g点的情况下,的方案数。一个点作为g点,只能限制同一行和一列上的数。只能比这个数小。而这个数又可以取2-k的值,行列上的数就是在比他小的范围内任选。这个需要o(n)累加。其他没限制的数就是任选。因为加权了。当图中有x个g点时,遍历这些g点的时候,就等于重复计算了x次。正好就等于加权后的值。然后又可以发现,其实每个点作为g点时。方案数都是相同的,因为可限制的数都是一行一列。所以值是一样的。最后就变成纯纯的快速幂了。

比赛时还是没能推出来数学题。太菜了。DP应该也能做,但是没想出来。
推导过程:

在这里插入图片描述

某个点作为Great Cell时的总方案数:

在这里插入图片描述

AC代码:

#include <bits/stdc++.h>
#define int long long
#define mk make_pair
using namespace std;
const int N = 3e5+11;
const int mod = 1e9+7;
int t,n,m,k;
int a[N];
 
int qpow(int a,int b){
    int res = 1;
    int tmp = a;
    while(b){
        if(b&1) res = (res*tmp) %mod;
        tmp = (tmp*tmp)%mod;
        b >>= 1;
    }
    return res;
}
 
signed main(){
    int t = 1,cas = 1;
    scanf("%lld",&t);
    while(t-- ){
        scanf("%lld%lld%lld",&n,&m,&k);
        int res = 0;
        for(int i = 0 ; i < k ; i ++){
            res = ((res+qpow(i,n+m-2)))%mod;
        }
        res = res*qpow(k,(n-1)*(m-1)%mod)%mod;
        res = res*n%mod*m%mod+qpow(k,n*m%mod) %mod;
        res %= mod;
        printf("Case #%lld: %lld\n",cas++,res);
    }
    return 0;
}

L. World Cup

题意:四个队伍两两对战打6场比赛,赢的3分,输了没分。平局一队一分。现在给出四个队伍的得分。判断这个得分是不是合法的。

思路:签到题。数据范围不大。直接枚举所有情况就完事了。{{0,1},{0,2},{0,3},{1,2},{1,3},{2,3}} 是所有的对局安排。然后对于每个对局,枚举胜负情况。然后记录可行方案数就好了。

AC代码:

#include <bits/stdc++.h>
#define int long long
#define mk make_pair
using namespace std;
const int N = 1e6+7;
const int mod = 1e9+7;
int t,n,m,k;
int a[10];
int a0,a1,a2,a3,a4;
int sum[N];
int game[6][2] = {{0,1},{0,2},{0,3},{1,2},{1,3},{2,3}};
int res = 0;
 
void dfs(int cnt){
    if(cnt == 6){
        //cout<<a[0]<<" "<<a[1]<<" "<<a[2]<<" "<<a[3]<<endl;
        if(a0 != a[0]) return ;
        if(a1 != a[1]) return ;
        if(a2 != a[2]) return ;
        if(a3 != a[3]) return ;
        res ++;
        return ;
    }
    int x = game[cnt][0];
    int y = game[cnt][1];
    // 1
    a[x] += 3;
    dfs(cnt+1);
    a[x] -= 3;
    // 2
    a[y] += 3;
    dfs(cnt+1);
    a[y] -= 3;
    //3
    a[x]++,a[y]++;
    dfs(cnt+1);;
    a[x]--,a[y]--;
}
 
signed main(){
    int t = 1,cas = 1;
    scanf("%lld",&t);
    while(t-- ){
        res = 0;
        scanf("%lld%lld%lld%lld",&a0,&a1,&a2,&a3);
        dfs(0);
        if(res == 0) {
            printf("Case #%lld: Wrong Scoreboard\n",cas++);
        }else if(res == 1){
            printf("Case #%lld: Yes\n",cas++);
        }else{
            printf("Case #%lld: No\n",cas++);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值