2017年第0届浙江工业大学之江学院程序设计竞赛决赛

A

qwb同时也是是之江学院的志愿者,暑期要前往周边地区支教,为了提高小学生的数学水平。她把小学生排成一排,从左至右从1开始依次往上报数。
玩完一轮后,他发现这个游戏太简单了。于是他选了3个不同的数x,y,z;从1依次往上开始报数,遇到x的倍数、y的倍数或z的倍数就跳过。如果x=2,y=3,z=5;
第一名小学生报1,第2名得跳过2、3、4、5、6,报7;第3名得跳过8、9、10,报11。
那么问题来了,请你来计算,第N名学生报的数字是多少?

二分+容斥
容斥的结果为xyz任意的倍数 w-cnt结果为不是xyz的倍数

#include <bits/stdc++.h>

#define LL long long 

using namespace std;

LL gcd(LL a,LL b){return b==0?a:gcd(b,a%b);}

LL lcm(LL a,LL b){
    LL ans;
    ans=a/gcd(a,b);
    LL tmp=LONG_LONG_MAX/ans;
    if (tmp<b) ans=-1;
    else ans*=b;
    return ans;
}
int main(){
    LL l,r,x,y,z,n,ans;
    while(~scanf("%lld%lld%lld%lld",&x,&y,&z,&n)){
        l=0;
        r=LONG_LONG_MAX;
        while(l+1<r){
            LL mid=(l+r)/2;
            ans=mid/x+mid/y+mid/z;
            LL t1=lcm(x,y);
            LL t2=lcm(y,z);
            LL t3=lcm(z,x);
            ans -=  mid/t1 + mid/t2 + mid/t3;
            LL t=lcm(t1,z);
            if (t!=-1) ans+=mid/t;
            if (mid-ans>=n) r=mid;
            else l=mid;
        }
        printf("%lld\n",r);
    }
    return 0;
}

B

做完了辣么多的数学题,qwb好好睡了一觉。但是他做了一个梦:
有一个nm的矩阵,qwb在这个矩阵的左上角(1,1),终点在右下角(n,m)。
每个格子中有小钱钱,也可能没有,还有可能是要交过路费的,并且行走方向必须是靠近终点的方向。
往下走一次只能走一格,往右走一次可以走一格也可以走到当前列数的倍数格。
比如当前格子是(x,y),那么可以移动到(x+1,y),(x,y+1)或者(x,yk),其中k>1。
qwb希望找到一种走法,使得到达右下角时他能够有最多的小钱钱。
你能帮助他吗?

DP
nmlogm

#include <bits/stdc++.h>

using namespace std;

int n,m;

int a[22][10005];
int f[22][10005];

int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++){
                scanf("%d",&a[i][j]);
                f[i][j]=-20000000;
            }
        f[1][1]=0;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++){
                f[i][j]+=a[i][j];
                if(f[i][j]>f[i+1][j])
                    f[i+1][j]=f[i][j];
                if(f[i][j]>f[i][j+1])
                    f[i][j+1]=f[i][j];
                for(int t=j+j;t<=m;t+=j)
                    if(f[i][j]>f[i][t])
                        f[i][t]=f[i][j];
            } 
        printf("%d\n",f[n][m]);
    }
    return 0;
} 

C

zjc的ACgirls队的队员最近比较忙,为了能够取得更好的比赛成绩,他们制定了一个m天a掉n题的计划,a掉一题可以是这m天的任何时候。
为了表示对acmer事业的热爱,队长wc要求每天必须至少要ac掉k题,这m天每天ac掉的题数可以用一个m元组表示。
设不同的m元组一共有c个,请问c的末尾有多少个0?(如果c是0,输出0)

先去掉每天必须完成的,然后加上隔板法求出答案。

Ck1n+k1

求其末尾0,即求约束2跟5中少的那个的个数。

#include <bits/stdc++.h>

#define LL long long

using namespace std;

LL n,m,k; 

LL C(LL n,LL m){
    LL num2=0,num5=0;
    for(LL i=2LL;i<=n;i*=2)
        num2+=n/i;
    for(LL i=5LL;i<=n;i*=5)
        num5+=n/i;
    for(LL i=2LL;i<=m;i*=2)
        num2-=m/i;
    for(LL i=5LL;i<=m;i*=5)
        num5-=m/i;
    for(LL i=2LL;i<=(n-m);i*=2)
        num2-=(n-m)/i;
    for(LL i=5LL;i<=(n-m);i*=5)
        num5-=(n-m)/i;
    return min(num2,num5);
}

int main(){
    while(~scanf("%lld%lld%lld",&n,&m,&k)){
        m-=n*k;
        if(m<0){
            puts("0");
            continue;
        }
        LL Zero=C(n+m-1,n-1);
        printf("%lld\n",Zero);
    }
    return 0;
} 

D

qwb又遇到了一道题目:
有一个序列,初始时只有两个数x和y,之后每次操作时,在原序列的任意两个相邻数之间插入这两个数的和,得到新序列。举例说明:
初始:1 2
操作1次:1 3 2
操作2次:1 4 3 5 2
……
请问在操作n次之后,得到的序列的所有数之和是多少

ai=ai13(x+y)

快速幂

[3011]

#include<cstdio> 
#include<cstring>
#include<iostream>
using namespace std;
typedef long long ll;
const int P = 100000000;
const int N=3;
ll n,m;

struct matrix{
    ll a[N][N];
    int row,col;
    matrix():row(N),col(N){memset(a,0,sizeof(a));}
    matrix(int x,int y):row(x),col(y){memset(a,0,sizeof(a));}
    ll* operator [] (int x){return a[x];}
    matrix operator * (matrix x){
        matrix tmp ;
        for (int i=0;i<=n+1;i++)
            for (int j=0;j<=n+1;j++){
                tmp[i][j]=0;
                for (int k=0;k<=n+1;k++)
                    tmp[i][j]=(tmp[i][j]+a[i][k]*x[k][j])%P;
            }
        return tmp;
    }   
    void operator *= (matrix x){*this = *this * x;}
    matrix operator ^ (ll x){
        matrix ret;
        for (int i=0;i<=n+1;i++)ret[i][i]=1;
        matrix tmp = *this;
        for (;x;x>>=1,tmp*=tmp){if(x&1)ret *=tmp;}
        return ret;
    }
    void print(){
        for (int i=0;i<=n+1;i++){
            for (int j=0;j<=n+1;j++)
                printf("%d ",a[i][j]);
            puts("");
        }
    }
};

int main(){
    ll x, y, t, ans;
    n=1;
    matrix a; 
    while(~scanf("%lld%lld%lld",&x,&y,&t)){
        ll tmp = (x+y)%P;
        a[0][0]=3;a[0][1]=1;
        a[1][0]=0;a[1][1]=1;
        a = a ^ t;
        ans = ((tmp*a[0][0]%P+P) - (a[0][1]*tmp) % P)%P+P;
        ans %= P;
        printf("%lld\n",ans);
    }
    return 0;
}

E

qwb和李主席打算平分一堆宝藏,他们想确保分配公平,可惜他们都太懒了,你能帮助他们嘛?

叫什么,折半搜索?

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const LL inf = 1e18;
double a[40];
double fi[1<<19],se[1<<19];
int cnt1,cnt2;
double sum=0,ans;
int n;
void dfs(int st,int ed,double sum,int flag){
    if(flag==1){
        if(st==ed+1){
            fi[cnt1++]=sum;
            return ;
        }
        dfs(st+1,ed,sum,flag);
        dfs(st+1,ed,sum+a[st],flag);
    }   
    if(flag==2){
        if(st==ed+1){
            se[cnt2++]=sum;
            return ;
        }
        dfs(st+1,ed,sum,flag);
        dfs(st+1,ed,sum+a[st],flag);
    }
}
int main(){
//  freopen("input.txt","r",stdin);
    while(scanf("%d",&n)!=EOF){
        sum=0;
        cnt1=0,cnt2=0;
        ans=(double)inf;
        for(int i=1;i<=n;i++){
            scanf("%lf",&a[i]);
            sum+=a[i];
        }
        dfs(1,n/2,0,1);
        dfs(n/2+1,n,0,2);
        sort(fi,fi+cnt1);
        sort(se,se+cnt2);
        for(int i=0;i<cnt1;i++) ans=min(ans,fabs(sum-2*fi[i]));
        for(int i=0;i<cnt2;i++) ans=min(ans,fabs(sum-2*se[i]));
        for(int l=0,r=cnt2; l<cnt1 && r>0;l++){
            while(r>1 && fi[l]+se[r-1]>sum/2.0) r--;
            ans=min(ans,fabs(sum-2*(fi[l]+se[r])));
            ans=min(ans,fabs(sum-2*(fi[l]+se[r-1])));
        }
        printf("%.2lf\n",ans);
    }
    return 0;
}

F

qwb has a lot of coins. One day, he decides to play a game with his friend using these coins. He first puts some of his coins into M piles, each of which is composed of Ni (1<=i<=M) coins. Then, the two players play the coin game in turns. Every step, one can remove one or more coins from only one pile. The winner is the one who removes the last coin.
Then comes the question: How many different ways the first player can do that will ensure him win the game?

nim博弈
详细问了百度。

#include <bits/stdc++.h>

using namespace std;

int n;
int s[2005];

int main(){
    while(~scanf("%d",&n)){
        int ans=0;
        for(int i=0;i<n;i++){
            scanf("%d",&s[i]);
            ans^=s[i];
        }
        if(!ans)
        printf("0\n");
        else{
            int tot=0;
            for(int i = 0; i < n;++i){
                int k = ans ^ s[i];
                if( k< s[i])
                    tot++;
            }
            printf("%d\n",tot);
        }
    }
    return 0;
}

G

某一天,qwb去WCfun面试,面试官问了他一个问题:把一个正整数n拆分成若干个正整数的和,请求出这些数乘积的最大值。
qwb比较猥琐,借故上厕所偷偷上网求助,聪明的你能帮助他吗?

分3 ,不足补2。剩下4就是4。

#include <bits/stdc++.h>

#define LL long long

using namespace std;

const LL MOD = 1e9+7;

int T;
LL n;

LL pow(LL a,LL n){
    if(n==0) return 1LL;
    LL tmp=pow(a,n/2);
    if(n&1) return tmp*tmp*a%MOD;
    return tmp*tmp%MOD;
}

int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%lld",&n);
        if(n<=4){
            printf("%d\n",n);
            continue;
        }
        LL t = n/3;
        LL p = n%3;
        LL ans;
        if(p==1) ans=pow(3LL,t-1)*4LL%MOD;
        if(p==2) ans=pow(3LL,t)*2LL%MOD;
        if(p==0) ans=pow(3LL,t);
        printf("%lld\n",ans);
    } 
    return 0;
}

H

qwb打算向学姐表白,可是学姐已经受够了他的骚扰,于是出了一个题想难住他:
已知一幅n个点m条边的无向图,定义路径的值为这条路径上最短的边的长度,
现在有 k个询问,
询问从A点到B点的所有路径的值的最大值。
qwb听完这个问题很绝望啊,聪明的你能帮帮他吗?

最短的最长?
首先做一遍最大生成树。。。然后lca查询。

#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
const int N = 150000;
int n,m,q;

struct gragh{
    struct Edge{
        int from,to,w;
        Edge(){}
        Edge(int x,int y,int z):from(x),to(y),w(z){}
        bool operator < (const Edge& a)const{
            return w < a.w;
        }
    }edges[210000],be[210000];
    int E,f[N],fa[N][20],di[N][20],dep[N];
    bool vis[N];
    vector<int >G[N];
    int F(int x){
        return f[x]==x?x:(f[x]=F(f[x]));
    }

    inline void link(int x,int y,int z){
        edges[++E]=Edge(x,y,z);
        G[x].push_back(E);
    }

    void build(){
        E=0;
        for (int i=1;i<=n;i++)G[i].clear();
        int x,y,z;
        for (int i=1;i<=n;i++)f[i]=i;
        for (int i=1;i<=m;i++){
            scanf("%d%d%d",&x,&y,&z);
            be[i]=Edge(x,y,z);
            f[F(x)]=F(y);
        }
    }

    void kruskal(){
        int treenum = 0;
        memset(vis,0,sizeof(vis));
        for (int i=1;i<=n;i++)if (!vis[F(i)]){
            treenum++;vis[F(i)]=1;
        }
        for (int i=1;i<=n;i++)f[i]=i;
        sort(be+1,be+m+1);
        int cnt = 0;
        for (int i=m;i>=1;i--){
            int x = be[i].from;
            int y = be[i].to  ;
            if (F(x)==F(y))continue;
            f[F(x)]=F(y);
            cnt++;
            link(x,y,be[i].w);
            link(y,x,be[i].w);
            if (cnt==n-treenum)break;
        }
    }

    void dfs(int x){
        vis[x] = 1;
        for (int i=1;i<=16;i++){
            if(dep[x]<(1<<i))break;
            fa[x][i]=fa[fa[x][i-1]][i-1];
            di[x][i]=min(di[x][i-1],di[fa[x][i-1]][i-1]);
        }
        for (int i=0;i<G[x].size();i++){
            Edge e = edges[G[x][i]];
            if (vis[e.to])continue;
            fa[e.to][0] = x;
            di[e.to][0] = e.w;
            dep[e.to] = dep[x]+1;
            dfs(e.to);
        }
    }

    int lca(int x,int y){
        if (dep[x]<dep[y])swap(x,y);
        int t = dep[x] - dep[y];
        for (int i=0;i<=16;i++)
            if ((1<<i)&t) x = fa[x][i];
        for (int i=16;i>=0;i--)
            if (fa[x][i]!=fa[y][i]){
            x=fa[x][i];y=fa[y][i];
        }
        if (x==y)return x;
        return fa[x][0];
    }

    int ask(int x,int f){//f:father
        int ans = INF;
        int t = dep[x]-dep[f];
        for (int i=0;i<=16;i++)if(t&(1<<i)){
            ans=min(ans,di[x][i]);
            x = fa[x][i];
        }
        return ans;
    }

    void work(){
        build();
        kruskal();
        memset(vis,0,sizeof(vis));
        for (int i=1;i<=n;i++)if(!vis[i])dfs(i);
        int x,y;
        while (q--){
            scanf("%d%d",&x,&y);
            if (F(x)!=F(y))puts("-1");
            else {
                int t = lca(x,y);
                x = ask(x,t);
                y = ask(y,t);
                printf("%d\n",min(x,y));
            }
        }
    }
}g;

int main(){
    for (;~scanf("%d%d%d",&n,&m,&q);)g.work();
    return 0;
}

J

qwb最近在做一个群众收入统计。ta非常懒,以至于忘记了今天领导要来视察。所以急忙催下属去做统计。
在接下来长度为n的时间里,每个单位时间都有事情发生,可能会发下以下两种事件:
1 下属递交了一份调查报告,由于太匆忙,上面只有一个整数x,代表一个居民的收入。
2 领导来视察了,领导会来询问,收入在区间[l,r]内的居民的平均收入,qwb需要给出回答。
qwb非常讨厌小数,所以qwb上报时都会省略小数部分。如果上报时统计的人数为0,qwb就暴露了他偷懒的事情,他就会zhizhiwuwu。

树状数组。考虑下0 。

#include <bits/stdc++.h>

#define LL long long

using namespace std;

int n,N=1000101,type,l,r;

LL a[1000502];
LL  s[1005002];

inline int lowbit(int x){
    return x&(-x);
}

inline int read(){  
    int x=0; char ch=getchar();  
    while (ch<'0' || ch>'9') ch=getchar();  
    while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); }  
    return x; 
}

inline void Add(int x,int delta){
    while(x<=N){
        a[x]+=1;
        s[x]+=delta;
        x+=lowbit(x);
    }
}

inline LL Suma(int x){
    LL sum=0;
    while(x>0){
        sum+=a[x];
        x-=lowbit(x);
    }
    return sum;
}

inline LL Sums(int x){
    LL sum=0;
    while(x>0){
        sum+=s[x];
        x-=lowbit(x);
    }
    return sum;
}

int main(){
    while(~scanf("%d",&n)){
        memset(a,0,sizeof a);
        memset(s,0,sizeof s);
        for(int i=1;i<=n;i++){
            type=read();
            if(type==0){
                l=read();
                Add(l+1,l);
            } else {
                l=read();r=read();
                l++;r++;
                LL number = Suma(r) - Suma(l-1);
                LL  sum = Sums(r) - Sums(l-1);
                if(number==0) puts("zhizhiwuwu");
                else {
                    printf("%lld\n",(LL)(sum/number));
                }
            }
        }
        puts("");
    }
    return 0;
}

K

qwb遇到了一个问题:将分数a/b化为小数后,小数点后第n位的数字是多少?
做了那么多题,我已经不指望你能够帮上他了。。。

这题我好烦,爆出负数了。

#include<bits/stdc++.h>
#define LL long long
using namespace std;
LL x,mod,n;
LL quick_pow(LL a,LL b){
    LL re=1,base=a%mod;
    while(b){
        if(b&1) re=(re*base)%mod;
        base=(base*base)%mod;
        b>>=1;
    }
    return re;
}
int main(){
//  freopen("input.txt","r",stdin);
    while(scanf("%lld%lld%lld",&x,&mod,&n)!=EOF){
        printf("%lld\n",x*quick_pow(10,n-1)%mod*10/mod);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值