zoukankan      html  css  js  c++  java
  • 2016年山东省acm比赛题解完全版

    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
    ",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
    ",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
    ",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
    ",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
    ",ans);
        }
        return 0;
    }
    View Code

    h.Memory Leak

    题意:顾名思义,内存泄漏吗,题意就是题目图片那个题意,没啥坑,比赛的时候的还以为掉坑了,哎

    分析:那就模拟呗,把三个整在一个char 数组里最好搞了,记录输入的三个数组的名字和开始结尾,然后输出的时候,就输出呗,直到遇到'',反正题目给了,最后肯定有''结尾

      当时比赛的时候,就这么写的,测试数据都过,不知道哪写错了

    #include <bits/stdc++.h>
    using namespace std;
    const int MAXN = 11111;
    typedef pair<int, int>pii;
    char a[MAXN];
    string tmp;
    string input;
    map<string, pii>m;
    
    int main(){
        ios::sync_with_stdio(false);
        int T;
        string cmd, name;
        cin >> T;
        while (T--){
            m.clear();
            cin.ignore();
            memset(a, 0, sizeof(a));
            getline(cin, input);
            istringstream sin(input);
            sin >> tmp;
            int pos = 0;
            while (sin >> tmp){
                int l = tmp.find('['), r = tmp.find(']'), length;
                name = tmp.substr(0, l);
                istringstream sz(tmp.substr(l + 1, r - l + 1));
                sz >> length;
                m[name] = pii(pos, pos + length);
                pos += length;
            }
            while (cin >> cmd >> name && cmd[0] != 'r'){
                pii sb = m[name];
                if (cmd == "gets"){
                    cin.ignore();
                    getline(cin, input);
                    for (int i = 0; i < input.length(); i++)
                        if (i + sb.first < sb.second)
                            a[i + sb.first] = input[i];
                        else
                            break;
                    if (sb.second - sb.first > input.length())
                        a[sb.first + input.length()] = '';
                }
                else
                {
                    cout << a + sb.first << endl;
                }
            }
        }
        return 0;
    }
    View Code

    iRock Paper Scissors

    题意:有n个,玩石头剪刀布游戏,每个人出拳10次,每个人可以和其他的任何人玩一次,输出每个人赢0-10次的次数

    分析:教练说,看上去像网络流,网络流解决一切问题,不过,看了测试代码,发现不是网络流,是hash+预处理

    我先捋捋思路,一会更新

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 1e5 + 7;
    const int Limit = 243; // 3^5
    
    int Win(int x, int y) {
        int ret = 0;
        for (int k = 0; k < 5; k ++) {
            int dig0 = x % 3, dig1 = y % 3;
            if (dig0 == (dig1 + 1) % 3) {
                ret ++;
            }
            x /= 3, y /= 3;
        }
        return ret;
    }
    
    vector<int> win[6][Limit], lose[6][Limit];
    
    void Init() {
        for (int i = 0; i < Limit; i ++) {
            for (int j = 0; j < Limit; j ++) {
                win[Win(i, j)][i].push_back(j);
                lose[Win(i, j)][j].push_back(i);
            }
        }
    }
    
    int T, cas, n, a[N][11], res[N][11], f[6][Limit][Limit];
    char ch[11];
    
    int main() {
        Init();
        cin >> T;
        while (T --) {
            scanf("%d", &n);
            for (int i = 0; i < n; i ++) {
                scanf(" %s", ch);
                for (int j = 0; j < 10; j ++) {
                    if (ch[j] == 'R') a[i][j] = 0;
                    if (ch[j] == 'P') a[i][j] = 1;
                    if (ch[j] == 'S') a[i][j] = 2;
                }
            }
            memset(f, 0, sizeof(f));
            memset(res, 0, sizeof(res));
            int tot = 0;
            for (int i = 0; i < n; i ++) {
                int mask0 = 0, mask1 = 0;
                for (int j = 0; j < 5; j ++) mask0 = mask0 * 3 + a[i][j];
                for (int j = 5; j < 10; j ++) mask1 = mask1 * 3 + a[i][j];
                int tot = 0;
                for (int j = 0; j <= 5; j ++) {
                    for(int libiao = 0;libiao<lose[j][mask0].size();libiao++){
                        int t = lose[j][mask0][libiao];
                        tot ++;
                        f[j][t][mask1] ++;
                    }
                }
            }
            for (int i = 0; i < n; i ++) {
                int mask0 = 0, mask1 = 0;
                for (int j = 0; j < 5; j ++) mask0 = mask0 * 3 + a[i][j];
                for (int j = 5; j < 10; j ++) mask1 = mask1 * 3 + a[i][j];
                for (int s0 = 0; s0 <= 5; s0 ++)
                for (int s1 = 0; s1 <= 5; s1 ++) {
                    for(int libiao = 0;libiao < win[s1][mask1].size();libiao++){
    
                        int t = win[s1][mask1][libiao];
                        res[i][s0 + s1] += f[s0][mask0][t];
                    }
                }
                res[i][0] --;
            }
            printf("Case #%d:
    ", ++ cas);
            for (int i = 0; i < n; i ++) {
                for (int j = 0; j <= 10; j ++) {
                    printf("%d%c", res[i][j], j == 10 ? '
    ' : ' ');
                }
            }
        }
        return 0;
    }
    View Code

    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!
    ");
            else
                printf("Tell you a joke, the execution of Paladin.
    ");
        }
    }
    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种操作,用最少的次数,把第一个数变成第二个数

    分析:开始我们都是把注意力集中在了如何把第一个转化为第二个数,只想着记录状态,然后暴力搜索,没有注意到test有1000条,也没有想到把移位操作和加减操作分开,

    试了各种千奇百怪的搜索,废话不多说,下面上干货

    这个呢就是预处理移位操作,就是原来某位的数字到了其他位置,我位移操作要要走多少步,那么如果用1 2 3 4 5 6表示数字a的6个数的下表,那么总共情况有6!钟,那么数字的位置都确定了,剩下的只要再加上和对应位数字的差就行了,但是还要注意到一点,举个例子 比如状态2 1 3 4 5 6,如果用V[213456表示123456到达这个状态的话,没法表示他对3456这四个位置的修改权利,只有你的下标走到过

    L-1,你才对L有修改的权利(思想类黑书钓鱼那道题),这样用6!*6就可以描述所有的移位状态

    换位操作,i可以和i-1,i+1进行交换,

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    using namespace std;
    typedef long long ll;
    #define rep(i , n) for(int i = 0 ; i < (int)n ; i++)
    #define rep1(i , x, y) for(int i = (int)x; i<=(int)y; i++)
    
    const int inf = 0x3f3f3f3f;
    int encode(int* a)
    {
        int num = 0 ;
        rep(i, 6)
        num = num * 10 + a[i];
        return num;
    }
    void decode(int x,int * a)
    {
        for(int i = 5 ; i>= 0 ; i--)
        {
            a[i] = x % 10;
            x/=10;
        }
    }
    const int N = 1e6 + 100;
    int vis[N][6][6], VIS[N][6];
    struct node
    {
        int s, p, max_;
        node(int s = 0,int p = 0, int max_ = 0) :s(s),p(p), max_(max_) {}
    };
    queue<node> q;
    void Push(int s, int p, int max_,int val)
    {
        if(vis[s][p][max_] == -1)
        {
            vis[s][p][max_] =  val + 1;
            VIS[s][max_] = min(vis[s][p][max_], VIS[s][max_]);
            q.push(node(s, p ,max_));
        }
    }
    void init_bfs()
    {
        memset(vis,-1,sizeof(vis));
        memset(VIS,inf,sizeof(VIS));
        VIS[123456][0] = 0;
        int a[7];
        rep(i, 6) a[i] = i + 1;
        q.push(node(encode(a), 0, 0));
        vis[encode(a)][0][0] = 0;
        while(!q.empty())
        {
            node u = q.front();
            q.pop();
            int val = vis[u.s][u.p][u.max_];
            if(u.p > 0)
            {
                Push(u.s, u.p - 1, u.max_, val);
                int b[7];
                decode(u.s, b);
                swap(b[u.p], b[u.p - 1]);
                int nts = encode(b);
                Push(nts, u.p, u.max_, val);
            }
            if(u.p < 5)
            {
                Push(u.s, u.p + 1, max(u.max_, u.p + 1), val);
                int b[7];
                decode(u.s, b);
                swap(b[u.p], b[u.p + 1]);
                int nts = encode(b);
                Push(nts, u.p, max(u.max_, u.p + 1), val);
            }
        }
    }
    int a[7], b[7];
    void solve()
    {
        int c[6] = {1, 2, 3, 4, 5, 6};
        int ans = inf;
        do
        {
            int all = 0, max_ = 0 ;
            rep(i, 6)
            {
                int fro = a[c[i] - 1];
                int to_ = b[i];
                if(fro != to_) max_ = max(max_, c[i] - 1 );
                all += abs(fro - to_);
            }
            int exc = inf;
            for(int i = max_ ; i< 6 ; i++)
                exc = min(exc, VIS[encode(c)][i]);
            all += exc;
    //        if(encode(c) == 612345 ){
    //              cout<<all <<" "<< exc<<" "<< max_ << endl;
    //        }
            ans = min(ans,all);
        }
        while(next_permutation(c, c + 6));
        printf("%d
    ",ans);
    }
    char s[100];
    void read(int* a)
    {
        scanf("%s",s);
        rep(i, 6){
            a[i] = s[i] - '0';
        }
    }
    int main()
    {
        init_bfs();
        int T;
        scanf("%d",&T);
        while(T--)
        {
            read(a);
            read(b);
            solve();
        }
        return 0;
    }
    View Code
  • 相关阅读:
    DFS
    离散化
    前缀和&差分
    数组运用_1-15 选择题
    数组运用_1-13 选择题
    数组运用_1-11 选择题
    数组运用_1-9 选择题
    数组运用_1-4 编程练习
    数组初始_2-22编程练习
    poj 3669 bfs(这道题隐藏着一个大坑)
  • 原文地址:https://www.cnblogs.com/jihe/p/5573378.html
Copyright © 2011-2022 走看看