Gym 101775 2017-2018 ACM-ICPC Asia East Continent League Final (ECL-Final 2017)

传送门

A.Chat Group   

    不难发现,题目中让我们求的式子为:

    而很显然,因为n相当的大,因此直接做的话绝对会超时,因此考虑将式子转化。

    根据组合数的公式,上述的式子可以转化为:

    因为此时的k比较小,因此我们利用组合数公式递推求解。

#include <bits/stdc++.h>
#define maxn 100005
using namespace std;
typedef long long ll;
ll inv[maxn+20];
const int mod=1e9+7;
void init(){
    inv[1]=inv[0]=1;
    for(int i=2;i<=maxn;i++){
        inv[i]=(mod-mod/i)*inv[mod%i]%mod;
    }
}
ll powmod(ll a,ll b){
    ll res=1;
    while(b){
        if(b&1) res=res*a%mod;
        b>>=1;
        a=a*a%mod;
    }
    return res;

}
int main()
{
    init();
    int t,n,k,cnt=0;
    scanf("%d",&t);
    while (t--){
        scanf("%d %d",&n,&k);
        ll res=1,y=n,sum=1;
        for (int i=1;i<k;i++){
            res=res*y%mod*inv[i]%mod;
            y--;
            sum=(res+sum)%mod;
        }
        ll ans=(powmod(2,n)-sum+mod)%mod;
        printf("Case #%d: %lld\n",++cnt,ans);
    }
    return 0;
}
View Code

B.Scapegoat

    首先必定是每一口锅都让一个替罪羊去背,因为要使得最后的方差最小,因此我们考虑根据值离总平均值的距离做判断。

    因此,我们必定是要让每一口锅平均分配出来的值尽可能的接近总的平均值。为此,我们需要对每一口锅分别记录,Var1=(严重值-平均值)^2 以及  Var2=(加了1个人分锅后的严重值-平均值)^2。而要使得在整体上答案更优,我们必定是首先选取 Var1-Var2比较大的(证明选取它能够使得该锅的值更接近总的平均值)。因此我们只需要用一个优先队列进行维护,每次不断取队顶的锅,将一个人分配到那口锅即可。

#include <bits/stdc++.h>
#define maxn 200005
using namespace std;
double ave;
struct Node{
    double all,var1,var2,cur;//Var1和Var2分别代表原来的值离平均值的距离以及(Var1-加上1个人分摊后的值离平均值的距离)
    int num;
    bool operator <(const Node &b)const{//在优先队列中维护Var2即可
        return var2<b.var2;
    }
    Node(double _all,int _num,double _cur){
        all=_all,num=_num,cur=_cur;
        var1=(cur-ave)*(cur-ave)*num;
        var2=var1-(all/(num+1)-ave)*(all/(num+1)-ave)*(num+1);
    }
};
priority_queue<Node>que;
int a[maxn];
int main()
{
    int t;
    scanf("%d",&t);
    int Case=0;
    while(t--){
        int n,m,M;
        scanf("%d%d",&n,&m);
        M=m;
        double sum=0;
        for(int i=0;i<n;i++){
            scanf("%d",&a[i]);
            sum+=a[i];
        }
        ave=sum/m;//计算平均值
        for(int i=0;i<n;i++){
            Node now=Node(a[i],1,a[i]);
            que.push(Node(a[i],1,a[i]));
        }
        m-=n;
        while(m--){
            Node now=que.top();
            que.pop();
            que.push(Node(now.all,now.num+1,now.all/(now.num+1)));
        }

        double res=0;

        for(int i=0;i<n;i++){//计算方差
            res+=(que.top().cur-ave)*(que.top().cur-ave)*que.top().num;
            que.pop();
        }
        res/=M;
        printf("Case #%d: %.8f\n",++Case,res);
    }
}
View Code

C.Traffic Light

#include<bits/stdc++.h>
using namespace std;
const int maxn=1007;
int main(){
    int t,cnt=0,n;
    scanf("%d",&t);
    while (t--){
        scanf("%d",&n);
        double x,y,sum=0,mx=0;
        for (int i=0;i<=n;i++) {
            scanf("%lf",&x);
            sum+=x;
        }
        for (int i=1;i<=n;i++){
            scanf("%lf%lf",&x,&y);
            mx=max(y,mx);
        }
        sum+=mx;
        printf("Case #%d: %.8f\n",++cnt,sum);
    }
    return 0;
}
View Code

D.Mr. Panda and Geometric Sequence

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
vector<ll>vec;
ll Pow[20];
int Count(ll n){
    int cnt=0;
    while(n){
        n/=10;
        cnt++;
    }
    return cnt;
}
void init(){
    int n=1e5;
    Pow[0]=1;
    for(int i=1;i<=16;i++) Pow[i]=Pow[i-1]*10;
    for(int p=1;p<=n;p++){
        for(int q=p+1;q<=n/p;q++){
            if(__gcd(p,q)>1) continue;
            for(int k=1;k<=n/p/q;k++){
                ll x=1ll*k*p*p,y=1ll*k*p*q,z=1ll*k*q*q;
                ll numx=Count(x),numy=Count(y),numz=Count(z);
                ll numall=numx+numy+numz;
                if(numall>15) break;
                ll now=z,res=x*Pow[numy+numz]+y*Pow[numz]+z;
                vec.push_back(res);
                while(1){
                    if(now%p!=0) break;
                    now=now*q/p;
                    if(numall+Count(now)>15) break;
                    numall+=Count(now);
                    res=res*Pow[Count(now)]+now;
                    vec.push_back(res);
                }
            }
        }
    }
    sort(vec.begin(),vec.end());
    vec.resize(unique(vec.begin(),vec.end())-vec.begin());
}
ll Sum(ll n){
    return upper_bound(vec.begin(),vec.end(),n)-vec.begin();
}
int main()
{
    int t;
    init();
    scanf("%d",&t);
    int Case=0;
    while(t--){
        ll l,r;
        scanf("%lld%lld",&l,&r);
        printf("Case #%d: %lld\n",++Case,Sum(r)-Sum(l-1));
    }
    return 0;
}
View Code

E.Snakebird


F.Good Number


G.Image Recognition


H.Mr. Panda and Birthday Song


I.PLAYERUNKNOWN'S BATTLEGROUNDS


J.Straight Master 

    可以发现3,4,5可以凑出任意的3以上的数,还可以发现这个数列一直到第(n+1)位必然是升降相对应的,所以直接维护一个差分,相隔三以上的就可以正的负的相互怼掉,判断最后所剩的是否是0就可以了

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
int T,n;
int a[maxn],b[maxn];
void read(int &ret){
    ret=0;
    char ch=getchar();
    while(ch>'9'||ch<'0') ch=getchar();
    while(ch>='0'&&ch<='9'){
        ret=ret*10+ch-'0';
        ch=getchar();
    }
}
int cas;
int main(){
    read(T);
    while(T--){
        read(n);
        for(int i=1;i<=n;i++) {read(a[i]);b[i]=a[i]-a[i-1];}
        b[n+1]=-a[n];
        bool flag=0;
        if(b[2]<0||b[3]<0){printf("Case #%d: No\n",++cas);continue;}
        long long sum=0;
        for(int i=1;i<=n+1;i++){
            if(b[i]>0) sum+=b[i];
            int nxt=i+3;
            if(nxt>n+1) break;
            else if(b[nxt]<0) sum+=b[nxt];
            if(sum<0){flag=1;break;}
        }
        if(flag||sum) printf("Case #%d: No\n",++cas);
        else printf("Case #%d: Yes\n",++cas);
    }
    return 0;
}
View Code

K.Downgrade

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=100005;
int val[maxn];
long long sum[maxn];
int main(){
    int T,cas=0;
    scanf("%d",&T);
    while(T--){
        ll A,B,n;
        scanf("%lld%lld%lld",&A,&B,&n);
        for(int i=1;i<=A;i++){scanf("%d",&val[i]);sum[i]=sum[i-1]+val[i];}
        int m=A;
        while((n--)){
            int tmp1,tmp2;
            tmp1=lower_bound(sum+1,sum+m+1,A)-sum;
            tmp2=A-sum[tmp1-1];
            if(tmp1==A) {
                B=tmp2;
                break;
            }
            A=tmp1,B=tmp2;
        }
        printf("Case #%d: %lld-%lld\n",++cas,A,B);
    }
    return 0;
}
View Code

L.SOS

    一步一步分析必胜态.
    分析以下4个情况
    n=4
    n=7
    n=8
    n=15
    很明显必胜态是n=7
    n=15的时候是可以调整为必胜态的
    所以最后就可以发现
    n<=6必定平手
    7<=n<=15 不是平手就是先手必胜
    15<n 分析出奇数时先手必胜,偶数时后手必胜

#include <bits/stdc++.h>
#define maxn 100005
using namespace std;
int main()
{
    int T,n;
    scanf("%d",&T);
    for(int cas=1;cas<=T;cas++){
        scanf("%d",&n);
        if(n<=6)printf("Case #%d: Draw\n",cas);
        else if((n&1))printf("Case #%d: Panda\n",cas);
        else if (n>=16) printf("Case #%d: Sheep\n",cas);
        else printf("Case #%d: Draw\n",cas);
    }
    return 0;
}
View Code

M.World Cup

    温暖的签到题,只需要知道小组赛时有48场比赛,16强有8场比赛,8强有4场比赛,半决赛有2场比赛,决赛有1场比赛即可。

    最后模拟一下就OK了。

#include<bits/stdc++.h>
using namespace std;
int di[5]={1,49,57,61,63};
int val[5];
int main(){
    int T;
    long long ans;
    scanf("%d",&T);
    int cas=0;
    while(T--){
        for(int i=0;i<5;i++) scanf("%d",&val[i]);
        ans=0;
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            int id;
            scanf("%d",&id);
            for(int j=4;j>=0;j--){
                if(id>=di[j]){
                    ans+=val[j];
                    break;
                }
            }
        }
        ans*=10000;
        printf("Case #%d: %lld\n",++cas,ans);
    }
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/Chen-Jr/p/9908637.html