码迷,mamicode.com
首页 > 其他好文 > 详细

2016年山东省acm比赛题解(差l和h)

时间:2016-06-10 12:21:38      阅读:470      评论:0      收藏:0      [点我收藏+]

标签:

a Julyed

题意:n个单词,每天最多背m个单词,最少背多少天

分析:水题,不解释

技术分享
#include<bits/stdc++.h>
using namespace std;

int main(){
    int t,n,m;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&m);
        int ans=n/m;
        if(n%m!=0)
          ans++;
        printf("%d\n",ans);
    }
    return 0;
}
View Code

b. Fibonacci

题意:把n分解为Fibonacci数列的和,并且两个数不能连续

分析:其实两个数不能连续没有用,证明一下如果n=f1+f2+x,分类讨论下,x=f2,n那么n=2*f1+f2=f2+f3=f4,如果x=f3,那么n=f1+f2+f3=f1+f4,如果x==f4  n=f1+f2+f4=f3+f4=f5,如果n>f4

n=f3+x

所以n从大到小依次减Fibonacci,然后倒序输出就ok了

技术分享
#include<bits/stdc++.h>
using namespace std;
const int maxn=105;
int d[maxn],sz;

void init(){
    d[0]=d[1]=1;
    for(sz=2;;sz++){
        d[sz]=d[sz-1]+d[sz-2];
        if(d[sz]>=1e9)
          break;
    }
}

int main(){
    init();
    int t,n;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        stack<int> s;
        int tmp=n;
        for(int i=sz;i>0;i--)
            if(d[i]<=n){
                s.push(d[i]);
                n-=d[i];
            }
            printf("%d=",tmp);
            int a=s.top();s.pop();
            printf("%d",a);
            while(!s.empty()){
                a=s.top();s.pop();
                printf("+%d",a);
            }
            puts("");

    }
    return 0;
}
View Code

c.Proxy

题意:0是本地计算机,n+1是服务器,1-n是代理服务器,给出每条线路的时间消耗,然后找到最短的0到n+1的路径,然后输出0处选择的第一个代理服务器,如如果不存在,输出-1,如果0-n+1直连且最短,输出0

分析:mdzz,读错题了,哎,说多了都是泪,都出的水题我们没出,dijkstra,把边倒着输入,然后找n+1-0的最短路,松弛操作记录前驱,特殊情况判断下就ok了

技术分享
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
const int INF=1e9;

struct Edge{
    int from,to,dist;
    Edge(int u,int v,int w):from(u),to(v),dist(w){}
};

struct HeapNode{
    int d,u;
    bool operator < (const HeapNode& r) const{
        return d>r.d;
    }
};

struct Dijkstra{
    int n,m;
    vector<Edge> edges;
    vector<int> G[maxn];
    bool done[maxn];
    int d[maxn];
    int p[maxn];

    void init(int n){
        this->n=n;
        for(int i=0;i<n;i++)
            G[i].clear();
        edges.clear();
    }

    void AddEdges(int from,int to,int dist){
        edges.push_back(Edge(from,to,dist));
        m=edges.size();
        G[from].push_back(m-1);
    }

    void dijkstra(int s){
        priority_queue<HeapNode> q;
        for(int i=0;i<n;i++)
            d[i]=INF;
        d[s]=0;
        memset(done,0,sizeof(done));
        q.push((HeapNode){0,s});
        while(!q.empty()){
            HeapNode x=q.top();q.pop();
            int u=x.u;
            if(done[u]) continue;
            done[u]=true;
            for(int i=0;i<G[u].size();i++){
                Edge& e=edges[G[u][i]];
                if(d[e.to]>d[u]+e.dist){
                    d[e.to]=d[u]+e.dist;
                    p[e.to]=u;
                    q.push((HeapNode){d[e.to],e.to});
                }
                else if(d[e.to]==d[u]+e.dist)
                  p[e.to]=min(p[e.to],G[u][i]);
            }
        }
    }
}dijkstra;

int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        int n,m;
        scanf("%d%d",&n,&m);
        dijkstra.init(n+2);
        int u,v,w;
        while(m--){
            scanf("%d%d%d",&u,&v,&w);
            dijkstra.AddEdges(v,u,w);
        }
        dijkstra.dijkstra(n+1);
        if(dijkstra.d[0]>=INF){
            puts("-1");
            continue;
        }
        if(dijkstra.p[0]==n+1){
            puts("0");
            continue;
        }
        printf("%d\n",dijkstra.p[0]);
    }
    return 0;
}
View Code

d.Swiss-system tournament

2*n个人,每个人有一个初始的分数,和能力值,按照分数排序,分数相同,序号小的在前面,然后每次(1 2)(3 4),这样的两个人比较,能力值大的+1分,小的不变,最后输出排名为k的人的编号

分析:zz题,当时没几个出的,思路题,想不出来没办法,要注意到失败的人是有序,胜利的人是有序的,+1后依然是有序的,两个数组分别存,然后按归并的思想往里插,O(n)时间完成排序,总时间复杂度O(n*logn+r*n)

技术分享
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int n,m,r;
struct node{
    int id,x,s;
    void read(int a,int b,int c){
        id=a;
        x=b;
        s=c;
    }
}v[maxn*2],v1[maxn],v2[maxn];

bool cmp(node a,node b){
    if(a.x==b.x)
      return a.id<b.id;
    return a.x>b.x;
}

void solve(){
    int l=0,r=0;
    for(int i=0;i<n;i+=2){
        int a=i,b=i+1;
        if(v[a].s<v[b].s||(v[a].s==v[b].s&&v[a].id>v[b].id))
          swap(a,b);
        v1[l++].read(v[a].id,v[a].x+1,v[a].s);
        v2[r++].read(v[b].id,v[b].x,v[b].s);
    }
    int a=0,b=0,c=0;
    while(a<l||b<r){
        if((b>=r)||(a<l&&(v1[a].x>v2[b].x||(v1[a].x==v2[b].x&&v1[a].id<v2[b].id))))
            v[c++]=v1[a++];
        else
          v[c++]=v2[b++];
        //printf("%d ",v[c-1].x);
    }
//    puts("");
}

int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d%d",&n,&r,&m);
        n*=2;
        for(int i=0;i<n;i++){
            scanf("%d",&v[i].x);
            v[i].id=i;
        }
        for(int i=0;i<n;i++)
          scanf("%d",&v[i].s);
        sort(v,v+n,cmp);
        while(r--)
          solve();
        printf("%d\n",v[m-1].id+1);
    }
    return 0;
}
View Code

e.The Binding of Isaac

题意:有一些房间,周围都是空地,求只与一个房间相邻的空地数

分析:这个题都出了吧,看到第一眼以为是个搜索,没想到就一水题,n,m周围都搞成空地,然后输入就行,之间判断每个空地周围房间数

技术分享
#include<bits/stdc++.h>
using namespace std;
const int maxn=105;
const int dx[]={0,0,1,-1};
const int dy[]={1,-1,0,0};
char g[maxn][maxn];
int n,m;
int judge(int x,int y){
    int count=0;
    for(int i=0;i<4;i++){
        int nx=x+dx[i];
        int ny=y+dy[i];
        if(nx<0||nx>n+1||ny<0||ny>m+1)
          continue;
        if(g[nx][ny]==#)
          count++;
    }
    return count==1?1:0;
}

int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&m);getchar();
        for(int i=0;i<=n+1;i++)g[i][0]=g[i][m+1]=.;
        for(int i=0;i<=m+1;i++)g[0][i]=g[n+1][i]=.;
        for(int i=1;i<=n;i++){
            scanf("%s",g[i]+1);
            getchar();
        }
        int ans=0;
        for(int i=0;i<=n+1;i++)
          for(int j=0;j<=m+1;j++)
            if(g[i][j]==#)
              continue;
            else
              ans+=judge(i,j);
        printf("%d\n",ans);
    }
    return 0;
}
View Code

f.Feed the monkey

题意:三个东西分别有n1,n2,n3个,每天取一个物品,但是三种物品连续取得不得超过d1,d2,d3个,问有多少取方案

分析:当时一看,算了下转态50^4*3,1e7多点,没问题,时间足够,而且非常多的状态达不到,就采用了记忆化搜索,当时脑残了,有个错就是找不到,遗憾,出来就找到了,悲哀,莫过于赛后过题

技术分享
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
int dp[55][55][55][55][3];
int n[3],num[3];

int dfs(int a,int b,int c,int d,int e){
    int& z=dp[a][b][c][d][e];
    if(a==0&&b==0&&c==0)return z=1;
    if(z!=-1)
      return z;
    ll ans=0;
    for(int i=0;i<3;i++){
        if(i==0&&a==0)continue;
        else if(i==1&&b==0)continue;
        else if(i==2&&c==0)continue;
        int p;
        if(e==i){
            p=d+1;
            if(p>num[i])continue;
        }
        else
          p=1;
        if(i==0)
            ans+=dfs(a-1,b,c,p,i);
        else if(i==1)
          ans+=dfs(a,b-1,c,p,i);
        else if(i==2)
          ans+=dfs(a,b,c-1,p,i);
        ans%=mod;
    }
    return z=(int)ans;
}


int main(){
    int t;
    cin>>t;
    while(t--){
        for(int i=0;i<3;i++)
          cin>>n[i];
        for(int i=0;i<3;i++)
            cin>>num[i];
        ll ans=0;
        memset(dp,-1,sizeof(dp));
        for(int i=0;i<3;i++){
            if(n[i]==0)
              continue;
            if(i==0)
                ans+=dfs(n[0]-1,n[1],n[2],1,i);
            else if(i==1)
              ans+=dfs(n[0],n[1]-1,n[2],1,i);
            else if(i==2)
              ans+=dfs(n[0],n[1],n[2]-1,1,i);
            ans%=mod;
        }
        cout<<ans<<endl;


    }
    return 0;
}
View Code

g.Triple Nim

题意:nim游戏都玩过吧,把n个数字分成三堆,两人采取最佳策略,先手输

分析:先手输,也就是说三堆异或为0,然后我就往二进制上想,先想到奇数无解,因为最后的那个1,没有其他的1和他去^,然后由此我想到对应位的1只能分解为下一位的两个1,当时没想到组合数,我蒙了一个公式,决定赌一发,wa了,然后我继续考虑n中二进制有4个1的情况,然后想到一个神奇的式子(3^3-1)/2,一试,2 3个1的时候也成立,然后就搞了,a了,赛后想了下原理,比如20,二进制分解为11110,第四位必须放两个1,然后就是剩下三个1的放法了,每个1有三种方法,也就是3^3,减去第三个数什么都没得到的情况,然后(1,3,4)和(1,4,3)是同一种情况,所以/2

技术分享
#include<bits/stdc++.h>
using namespace std;

int main(){
    int t,n;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        if(n&1){
            puts("0");
            continue;
        }
        int count=-1;
        for(int i=1;i<=31;i++)
            if(n&(1<<i))
              count++;
        long long ans=pow(3,count)-1;
        ans/=2;
        printf("%lld\n",ans);
    }
    return 0;
}
View Code

h.Memory Leak

题意:

分析:

iRock Paper Scissors

题意:

分析:

j Execution of Paladin

题意:http://hs.178.com/201606/259352896164.html

分析:分析毛啊,没玩过炉石的伤不起啊,就这样吧,队友写的

技术分享
#include<cstdio>
#include<queue>
#include<functional>
#include <iostream>
#include <vector>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
string s;
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        getchar();
        int a=0,b=0,c=0;
        for(int i=0;i<n;i++)
        {
            getline(cin,s);
            if(s[0]==M)
                a++;
            if(s[0]==B)
                b++;
            if(s[0]==O)
                c++;
        }
        int cnt=2*(b+c)+2*a*(b+c)+(n-1)*c;
        if(cnt>=m)
            printf("Mrghllghghllghg!\n");
        else
            printf("Tell you a joke, the execution of Paladin.\n");
    }
}
View Code

k.Reversed Words

题意:不用说了,一看就知道,直接上代码

技术分享
#include<bits/stdc++.h>
using namespace std;
string s;
int main(){
    int t;
    scanf("%d",&t);getchar();
    while(t--){
        getline(cin,s);
        stack<string> ans;
        string tmp="";
        int len=s.length();
        for(int i=len-1;i>=0;i--)
            if(s[i]!= )
              tmp+=s[i];
            else{
                ans.push(tmp);
                tmp="";
            }
        cout<<tmp;
        while(!ans.empty()){
            tmp=ans.top();
            ans.pop();
            cout<<" "<<tmp;
        }
        cout<<endl;
    }
    return 0;
}
View Code

l Password

题意,6种操作,用最少的次数,把第一个数变成第二个数

分析:都是6位数,感觉记忆化搜索就可以搞,10^6*6,不大

2016年山东省acm比赛题解(差l和h)

标签:

原文地址:http://www.cnblogs.com/jihe/p/5573378.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!