2016山东省第七届ACM大学生程序设计竞赛题解

A Julyed
答案每一个数对后面整除,若不能整除,答案为整除+1。

#include<iostream>
#include<stdio.h>

using namespace std;

int main()
{
    int t;
    cin>>t;
    while(t--){
        double a,b;
        cin>>a>>b;
        double c=a/b;
        int d= c;
        if(c==d){
            cout<<d;
        }else{
            cout<<d+1;
        }
        cout<<"\n";

    }
    return 0;
}

B Fibonacci
把一个数字拆成许多不连续的斐波那契数字之和,可以找到贪心的策略,从大向小能拆必拆!

#include<iostream>
#include<stdio.h>
#include<queue>
#include<vector>
#include<string.h>
#include<algorithm>
using namespace std;

const int maxn=1e2+10;
const int mod=1e9+7;
int f[maxn];
int sz=0;
int ans[maxn];
void init()
{
    f[1]=1;
    f[2]=2;
    for(int i=3;i<=45;i++){
        f[i]=f[i-1]+f[i-2];
        if(f[i]>mod){
            sz=i;break;
        }
    }
}
int main()
{
    init();
    int T;
    scanf("%d",&T);
    while(T--){
        int n;
        scanf("%d",&n);
        int tmp=n;
        bool flag=0;int cs=0;
        for(int i=sz;i>=1;i--){
            if(flag==0&&n>=f[i]){
                n-=f[i];flag=1;ans[++cs]=f[i];
            }
            else if(flag==1)flag=0;
        }
        if(n==0){
            printf("%d=%d",tmp,ans[cs]);
            for(int i=cs-1;i>=1;i--){
                printf("+%d",ans[i]);
            }
        }
        else printf("-1");
        printf("\n");
    }
    return 0;
}

C Proxy
保存路径的最短路

#include<iostream>
#include<stdio.h>
#include<queue>
#include<vector>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn = 1000+33;
const int inf = 0x3f3f3f3f;
int n,m;
vector<int>G[maxn];
vector<int>len[maxn];
int pre[maxn];
int vis[maxn],dis[maxn];
void spfa(int s,int t)
{

    for(int i=0;i<=n+1;i++){
        vis[i]=0;
        dis[i]=inf;
    }
    queue<int>q;
    dis[0]=0;
    q.push(s);
    while(!q.empty()){
        int u = q.front();
        q.pop();
        vis[u]=0;
        for(int i=0;i<G[u].size();i++){
            int v=G[u][i];
            if(dis[v]>dis[u]+len[u][i]){
                dis[v]=dis[u]+len[u][i];
                pre[v]=u;
                if(!vis[v]){
                    vis[v]=1;
                    q.push(v);
                }
            }else if(dis[v]==dis[u]+len[u][i]&&pre[v]>u){
                pre[v]=u;
            }
        }
    }
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        for(int i=0;i<=n+1;i++){
            G[i].clear();
            len[i].clear();
            pre[i]=0;
        }
        for(int i=1;i<=m;i++){
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            G[u].push_back(v);
            len[u].push_back(w);
        }
        spfa(0,n+1);
        int now=n+1;
        if(dis[n+1]==inf){
            printf("-1\n");
            continue;
        }
        int ans=0;
        while(now){
            ans=now;
            now=pre[now];
        }
        if(ans==n+1){
            printf("0\n");
        }else{
            printf("%d\n",ans);
        }
    }


    return 0;
}

D Swiss-system tournament
模拟归并排序,在进行r轮操作的时候,我们发现其中的一半数字被调出来++,另一半则不变,那么这两个子数组的单调性是不发生变化的,所以可以归并!

#include<iostream>
#include<string.h>
#include<stdio.h>
#include<algorithm>
using namespace std;
const int maxn=1e5+10;
struct node{
    int id,wl,sc;
}a[maxn<<1],b[maxn],c[maxn];
int n,r,q,tmp;
bool cmp(node a,node b)
{
    if(a.sc!=b.sc) return a.sc>b.sc;
    else return a.id<b.id;
}
void merge_sort()
{
    for(int i=1;i<=r;i++)
    {
        int l1=0,l2=0;
        for(int j=1;j<=tmp;j+=2){
            l1++; l2++;
            if(a[j].wl<a[j+1].wl) a[j+1].sc++,b[l1]=a[j+1],c[l2]=a[j];
            else a[j].sc++,b[l1]=a[j],c[l2]=a[j+1];
        }
        l1=l2=1;int k=0;
        while(l1<=n&&l2<=n)
        {
//            if(b[l1].sc<c[l2].sc) a[++k]=c[l2++];
//        //  if(b[l1].sc<c[l2].sc) a[++k]=c[l2++];
//            else if(b[l1].sc>c[12].sc) a[++k]=b[l1++];
//        //  else if(b[l1].sc>c[l2].sc) a[++k]=b[l1++];
//            else {
//        //  else {
//                if(b[l1].id<c[l2].id) a[++k]=b[l1++];
//            //  if(b[l1].id<c[l2].id) a[++k]=b[l1++];
//                else a[++k]=c[l2++];
//            //  else a[++k]=c[l2++];
//            }
            if(b[l1].sc<c[l2].sc) a[++k]=c[l2++];
            else if(b[l1].sc>c[l2].sc) a[++k]=b[l1++];
            else {
                if(b[l1].id<c[l2].id) a[++k]=b[l1++];
                else a[++k]=c[l2++];
            }
        }
        while(l1<=n) a[++k]=b[l1++];
        while(l2<=n) a[++k]=c[l2++];
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d",&n,&r,&q);tmp=2*n;
        for(int i=1;i<=tmp;i++){
            a[i].id=i;scanf("%d",&a[i].sc);
        }
        for(int i=1;i<=tmp;i++){
            scanf("%d",&a[i].wl);
        }
        sort(a+1,a+1+tmp,cmp);
        merge_sort();
        printf("%d\n",a[q].id);
    }
    return 0;
}

E The Binding of Isaac
基本的搜索题,找到秘密房间的数量。只和一个#相连的外围房间被视作秘密房间。

#include<iostream>
#include<stdio.h>
#include<string>
#include<string.h>
#include<algorithm>
using namespace std;

char mp[111][111];
int flag[111][111];
int dir[4][2]={0,1,0,-1,1,0,-1,0};

int n,m;
int check(int x,int y)
{
    if(mp[x][y]=='#') return 0;
    int ans=0;
    for(int i=0;i<4;i++){
        int xx = x+dir[i][1];
        int yy = y+dir[i][0];
        if(xx>=1&&xx<=n&&yy>=1&&yy<=m){
            if(mp[xx][yy]=='#')
                ans++;
        }
    }
    if(ans>1) return 0;
    return 1;
}


int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        memset(mp,0,sizeof(mp));
        for(int i=1;i<=n;i++){
            scanf("%s",mp[i]+1);
        }
        memset(flag,0,sizeof flag);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(mp[i][j]=='#'){
                    int x=i,y=j;
                    for(int k=0;k<4;k++){
                        int xx=x+dir[k][0];
                        int yy=y+dir[k][1];
                        if(check(xx,yy)){
                            flag[xx][yy]=1;
                        }
                    }
                }
            }
        }
        int ans=0;
        for(int i=0;i<=n+1;i++){
            for(int j=0;j<=m+1;j++){
                if(flag[i][j]) ans++;
            }
        }
        printf("%d\n",ans);
    }

    return 0;
}

F Feed the monkey
记忆化搜索|| DP D P dp[i][j][k][x] d p [ i ] [ j ] [ k ] [ x ] 表示当前还剩i个第一种水果,j个第二种水果,k个第三个水果没有分配并且当前以k水果结尾的方案数。

DP D P :

#include<iostream>
#include<string.h>
#include<stdio.h>
#include<algorithm>
#include<math.h>
using namespace std;
const int maxn = 1e5 + 10;
#define ll long long int
const ll mod = 1e9 + 7;
ll dp[55][55][55][3];

int main()
{
    int T; int n1, n2, n3, d1, d2, d3;
    scanf("%d", &T);
    while (T--) {
        scanf("%d %d %d %d %d %d", &n1, &n2, &n3, &d1, &d2, &d3);
        memset(dp, 0, sizeof dp);
        for (int i = 1; i <= min(d1, n1); i++) dp[n1 - i][n2][n3][0] = 1;
        for (int i = 1; i <= min(d2, n2); i++) dp[n1][n2 - i][n3][1] = 1;
        for (int i = 1; i <= min(d3, n3); i++) dp[n1][n2][n3 - i][2] = 1;
        for (int i = n1; i >= 0; i--)
            for (int j = n2; j >= 0; j--)
                for (int k = n3; k >= 0; k--) {
                    if ((i + j + k) == (n1 + n2 + n3)) continue;
                    for (int p = 1; p <= min(i, d1); p++) {
                        dp[i - p][j][k][0] = (dp[i - p][j][k][0] + (dp[i][j][k][1] + dp[i][j][k][2]) % mod) % mod;
                    }
                    for (int p = 1; p <= min(j, d2); p++) {
                        dp[i][j - p][k][1] = (dp[i][j - p][k][1] + (dp[i][j][k][0] + dp[i][j][k][2]) % mod) % mod;
                    }
                    for (int p = 1; p <= min(k, d3); p++) {
                        dp[i][j][k - p][2] = (dp[i][j][k - p][2] + (dp[i][j][k][1] + dp[i][j][k][0]) % mod) % mod;
                    }
                }
        ll ans = 0;
        for (int i = 0; i < 3; i++) (ans += dp[0][0][0][i]) %= mod;
        printf("%lld\n", ans);
    }
    return 0;
}

记忆化搜索

#include<iostream>
#include<stdio.h>
#include<queue>
#include<vector>
#include<string.h>
#include<algorithm>
using namespace std;
#define  LL long long

const LL mod=1000000007;
LL dp[55][55][55][4];
LL d1,d2,d3;
int vis[55][55][55][4];

LL dfs(LL x,LL y,LL z,LL pre)
{
    LL num=0;
    LL k=0;
    if(x!=0) k=1,num++;
    if(y!=0) k=2,num++;
    if(z!=0) k=3,num++;
    if(num==0) return 1;
    if(num==1){
        if(k==1&&x<=d1) return 1;
        if(k==2&&y<=d2) return 1;
        if(k==3&&z<=d3) return 1;
        return 0;
    }
    if(pre!=-1&&vis[x][y][z][pre]) return dp[x][y][z][pre];
    LL xx=min(x,d1);
    LL yy=min(y,d2);
    LL zz=min(z,d3);
    LL ans=0;
    if(pre==-1){
        for(LL i=1;i<=xx;i++){
            (ans+=dfs(x-i,y,z,1))%=mod;
        }
        for(LL i=1;i<=yy;i++){
            (ans+=dfs(x,y-i,z,2))%=mod;
        }
        for(LL i=1;i<=zz;i++){
            (ans+=dfs(x,y,z-i,3))%=mod;
        }
    }
    if(pre==1){
        for(LL i=1;i<=yy;i++){
            (ans+=dfs(x,y-i,z,2))%=mod;
        }
        for(LL i=1;i<=zz;i++){
            (ans+=dfs(x,y,z-i,3))%=mod;
        }
    }
    if(pre==2){
        for(LL i=1;i<=xx;i++){
            (ans+=dfs(x-i,y,z,1))%=mod;
        }

        for(LL i=1;i<=zz;i++){
            (ans+=dfs(x,y,z-i,3))%=mod;
        }
    }
    if(pre==3){
        for(LL i=1;i<=xx;i++){
            (ans+=dfs(x-i,y,z,1))%=mod;
        }
        for(LL i=1;i<=yy;i++){
            (ans+=dfs(x,y-i,z,2))%=mod;
        }

    }
    if(pre!=-1)  dp[x][y][z][pre]=ans,vis[x][y][z][pre]=1;
    return ans;
}

int main()
{
    LL T;
    scanf("%lld",&T);
    while(T--){
        LL n1,n2,n3;
        scanf("%lld%lld%lld%lld%lld%lld",&n1,&n2,&n3,&d1,&d2,&d3);
        for(int i=0;i<=n1;i++)
            for(int j=0;j<=n2;j++)
                for(int k=0;k<=n3;k++)
                    for(int t=0;t<=3;t++)
                        vis[i][j][k][t]=0;
        cout<<dfs(n1,n2,n3,-1)<<endl;

    }

    return 0;
}

G Triple Nim
博弈题目,要求一个数字分成三个数字并且这三个数字的异或和为0。暴力打表,找到在二进制每增加一个高位1,答案为之前的三倍加一。即 ans[i]=ans[i1]3+1 a n s [ i ] = a n s [ i − 1 ] ∗ 3 + 1 ;

#include<iostream>
#include<stdio.h>
#include<queue>
#include<vector>
#include<string.h>
#include<algorithm>
using namespace std;

const int maxn=1e2+10;
const int mod=1e9+7;

int mp[33][33][33];

void f(int x)
{
    int ans=0;
    for(int i = 1;i<=500;i++){
        for(int j=i+1;j<=500;j++){
            for(int k=j+1;k<=500;k++){
                if(i+j+k!=x) continue;
                if((i^j^k)==0)
                    ans++;
            }
        }
    }
    cout<<x<<" "<<ans<<endl;

}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        int n;
        scanf("%d",&n);
        if(n&1){
            printf("0\n");
        }else{
            int num=0;
            while(n){
                if(n&1) num++;
                n>>=1;
            }
            if(num==1){
                printf("0\n");
            }else{
                long long int ans = 1;
                for(int i=2;i<num;i++){
                    ans=ans*3+1;
                }
                printf("%lld\n",ans);
            }
        }
    }


    return 0;
}

H Memory Leak
内存分配的模拟题
I Rock Paper Scissors
J Execution of Paladin
对三张炉石传说卡牌直接模拟搞

#include<iostream>
#include<stdio.h>
#include<queue>
#include<vector>
#include<string.h>
#include<algorithm>
using namespace std;

const int maxn=1e2+10;
const int mod=1e9+7;


int main()
{
    int T;
    cin>>T;
    while(T--){
        int n,hp;
        scanf("%d %d",&n,&hp);
        char s[maxn];
        int lingjun=0;
        int c21=0;
        int old=0;
        getchar();
        for(int i=1;i<=n;i++){
            gets(s);
            if(s[0]=='M'){
                lingjun++;
            }
            if(s[0]=='B'){
                c21++;
            }
            if(s[0]=='O'){
                old++;
            }
        }
        int atk=0;
        atk+=c21*(2+lingjun*2);
        atk+=old*(lingjun*2+2+n-1);
        if(hp-atk>0){
            printf("Tell you a joke, the execution of Paladin.\n");
        }else{
            printf("Mrghllghghllghg!\n");
        }
    }

    return 0;
}

K Reversed Words
每个单词反向输出

#include<iostream>
#include<stdio.h>
#include<string>
#include<algorithm>
using namespace std;

int main()
{
    int T;
    while(~scanf("%d",&T)&&T){
        string s;
        while(T--){
        while(cin>>s){
            char c;
            reverse(s.begin(),s.end());
            cout<<s;
            c=getchar();
            if(c=='\n')
                break;
            else{
                printf(" ");
            }
        }
            printf("\n");

        }
    }
    return 0;
}

L Password

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值