山东省第七届ACM程序设计竞赛

本文解析了SDUTOJ在线裁判平台上的多个竞赛题目,包括简单数学运算、字符串操作、图论最短路径、动态规划等算法题目的实现思路与代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

sdutoj 3560 - 3570 http://acm.sdut.edu.cn/sdutoj/problem.php?page=26

A

水题

#include<iostream>  
#include<cstdio>  
#define mem(a,x) memset(a,x,sizeof(a))  
using namespace std;  
typedef long long ll;  
const int N = 100010;int a[5];  
  
int main(){  
    int t;  
    scanf("%d",&t);  
    while(t--){  
        int a,b;scanf("%d%d",&a,&b);  
        printf("%d\n",a/b + (a%b!=0));  
    }  
    return 0;  
}  

B

二分,每次在FIb中找与当前所需数最接近的。。

//好吧,我们当时就是这么做的
#include<iostream>  
#include<cstdio>  
#include<algorithm>  
#include<cstring>  
#define mem(a,x) memset(a,x,sizeof(a))  
using namespace std;  
typedef long long ll;  
const int N = 100010;int a[5];  
char s[50];  
int f[111];  
int ans[111];  
int main(){  
    int t;  
    scanf("%d",&t);  
    f[0] = 1; f[1] = 2;  
    int r  =0;  
    for(int i=2;;i++){  
        f[i] = f[i-1] + f[i-2];  
        if(f[i-2] + f[i-1] > 1e9) {  
           r = i;  
           break;  
        }  
  
    }  
    //cout<<r<<endl;  
    while(t--){  
        mem(ans,0);int l = 0;  
        int n;scanf("%d",&n);  
        printf("%d=",n);  
        int rear = n;  
        int fir = 1;  
        while(rear){  
            int po = lower_bound(f,f+r,rear) - f;  
            if(po!=0 && f[po] > rear) po--;  
            ans[l++] = f[po];  
            rear-= f[po];  
        }  
        sort(ans,ans+l);  
        for(int i=0;i<l;i++){  
            if(i!=l-1)  
                printf("%d+",ans[i]);  
            else  
                printf("%d\n",ans[i]);  
        }  
  
    }  
    return 0;  
}  

C,简单的最短路。

让你找能否从节点n+1连通到节点0,不能输出-1。如果能,则找出从节点n+1到节点0最短的那条通路,输出这条通路中与0相连的节点序号。如果有多条通路,输出节点序号最小的那个,如果n+1节点与0节点直接相连,并且路径也是最短,则输出0;

#include<iostream>  
#include<cstdio>  
#include<algorithm>  
#include<queue>  
#include<cstring>  
#define mem(a,x) memset(a,x,sizeof(a))  
#define INF 0x3f3f3f3f  
using namespace std;  
typedef long long ll;  
const int MAXN = 2020;  
int n,m;  
struct node{  
    int v, len;  
    bool operator < (const node & t) const{  
        return len > t.len;  
    }  
    node(int v = 0, int len = 0):v(v), len(len){}  
}tp[MAXN];  
vector<node> G[MAXN];  
bool vis[MAXN];  
int dis[MAXN];  
void Init(int n){  
    for(int i = 0; i <= n; i++){  
        vis[i] = false;  
        G[i].clear();  
        dis[i] = INF;  
    }  
}  
int dijstra_heap(int s){  
    priority_queue<node>Q;  
    dis[s] = 0;  
    //vis[s] = 1;  
    Q.push(node(s,0));  
    while(!Q.empty()){  
        node now = Q.top();  
        Q.pop();  
        int v = now.v;  
        if(vis[v]) continue;  
        vis[v] = true;  
        for(int i=0;i<G[v].size();i++){  
            int v2 = G[v][i].v; int len = G[v][i].len;  
            if(!vis[v2] && dis[v] + len <dis[v2]){  
                dis[v2] = dis[v] + len ;  
                //cout<<" ss"<<dis[v2]<<endl;  
                Q.push(node(v2,dis[v2])); //讲 dis[v2]放入堆中,利用logn的效率找到  
                                            //距离最短的节点  
            }  
        }  
    }  
    return dis[0];  
}  
int main(){  
  
    int t;scanf("%d",&t);  
    while(t--){  
        scanf("%d%d",&n,&m);  
        Init(n+1);int l = 0;  
        int a,b,c;int tt = -1;  
        for(int i=0;i<m;i++){  
            scanf("%d%d%d",&a,&b,&c);  
            G[b].push_back(node(a,c));  
            if(a == 0){  
                tp[l++] = node(b,c);  
            }  
        }  
  
        int ans = dijstra_heap(n+1);  
        if(ans == INF){  
                //cout<<"bug"<<endl;  
            printf("-1\n");continue;  
        }  
        else{  
            int maxi = 0,maxx = INF;  
            for(int i=0;i<l;i++){  
                tp[i].len += dis[tp[i].v];  
                if(tp[i].len < maxx){  
                    maxx = tp[i].len ;  
                    maxi = tp[i].v;  
                }  
            }  
            for(int i=0;i<l;i++){  
                if(tp[i].len == maxx){  
                    maxi = min(maxi,tp[i].v);  
                }  
            }  
            int flag = 0;  
            for(int i=0;i<l;i++){  
                if(tp[i].v == n+1 && tp[i].len == maxx){  
                    printf("0\n"); flag = 1;break;  
                }  
            }  
            if(!flag)  
                printf("%d\n",maxi);  
        }  
    }  
    return 0;  
}  
D

占坑

E

水题。

#include<iostream>  
#include<cstdio>  
#include<algorithm>  
#include<cstring>  
#define mem(a,x) memset(a,x,sizeof(a))  
using namespace std;  
typedef long long ll;  
const int N = 100010;int a[5];  
char s[50];  
int f[111];  
int ans[111];  
char G[111][111];  
int main(){  
    int t;  
    scanf("%d",&t);  
    while(t--){  
        int n,m;scanf("%d%d",&n,&m);  
        mem(G,'.');  
        for(int i=1;i<=n;i++){  
            for(int j=1;j<=m;j++)  
                scanf(" %c",&G[i][j]);  
        }  
        int ans = 0;  
        for(int i=0;i<=n+1;i++){  
            for(int j=0;j<=m+1;j++){  
                if(G[i][j] =='.'){  
                    int l = 0;  
                    if(i-1>=0 && G[i-1][j] =='#') l++;  
                    if(j-1>=0 && G[i][j-1] =='#') l++;  
                    if(i<n+1 && G[i+1][j] =='#') l++;  
                    if(j<m+1 && G[i][j+1] =='#') l++;  
                    if(l == 1) ans++;  
                }  
            }  
        }  
        printf("%d\n",ans);  
    }  
    return 0;  
}  


F

占坑

G

规律题,用NIM的方法(3个数异或)打出表来发现了规律。

奇数都是0,偶数的话发现都是1,4,13,40,,3n+1. 转换成二进制后发现与二进制中1的个数有关。

2个1,是1,3个1是4,4个1是13.。。

f[n] = f[n-1]*3 + 1

f[n-1]*3 = f[n-2]*9 + 3

f[n] = f[n-2]*9 + (1+3)

f[n] = f[n-3]*27 + (1 + 3 + 9)

这样推下去,得出

f[n] = f[1] *(3^(n-1)) + (1-3^(n-1))/(1-3)   。。。 (用到了等比数列求和公式 Sn = a1(1-q^n))/(1-q))

化简一下 f[n] = (3^n - 1)/2   (这里的n是二进制中1的个数-1)


这里学到一个gcc编译器的内建函数,__builtin_popcount(x)

直接统计整数x转换成2进制中有多少1。

#include<iostream>  
#include<cstdio>  
#include<algorithm>  
#include<queue>  
#include<cstring>  
#include<cmath>  
#define mem(a,x) memset(a,x,sizeof(a))  
#define INF 0x3f3f3f3f  
using namespace std;  
typedef long long ll;  
const int MAXN = 2020;  
int main(){  
    int T;scanf("%d",&T);  
    while(T--){  
        ll n;scanf("%lld",&n);  
        if(n < 6 || n&1) printf("0\n");  
        else{  
            int ans = __builtin_popcount(n);  
            if(ans <=1)printf("0\n");  
            else{  
                ans--;  
                printf("%lld\n",((ll)pow(3,ans)-1)/2);  
            }  
            //cout<<ans<<endl;  
  
        }  
    }  
    return 0;  
}  

H

//学习别人的做法,自己的找不出错了。。不过这个代码更省内存吧

#include<bits/stdc++.h>
using namespace std;
const int M =11111;
struct node{
    int l,r;
}e[M];
int top;
char s[M];
char c[M][M/10];
char op[M];
int main(){
    int T;scanf("%d",&T);
    while(T--){
        memset(s,0,sizeof(s));
        int pos = 0, top = 0;
        scanf("%s",op);
        while(true){
            scanf("%s",op);
            int len = strlen(op);
            int num = 0, i = 0;
            for(i = 0;i < len ; i++){
                if(op[i] != '[') c[top][i] = op[i];
                else break;
            }
            c[top][i] = '\0';
            for(i++;i<len;i++){
                if(op[i] == ']') break;
                num = num * 10 + op[i] - '0'; // 学习了
            }
            e[top].l = pos;
            e[top].r = pos + num;
            pos += num;
            top++;
            char ss = getchar();
            if (ss == '\n') break;
        }
        while(1){
            scanf("%s",op);
            if(op[0] == 'r'){
                scanf("%s",op); break;
            }
            else if(op[0] == 'c'){
                scanf("%s",op);
                for(int i = 0;i< top ;i++){
                    if(strcmp(op,c[i]) == 0){
                        for(int j=e[i].l;j<pos;j++){
                            if(s[j] == '\0') break;
                            printf("%c",s[j]);
                        }
                        printf("\n");
                        break;
                    }
                }
            }
            else if(op[0] == 'g'){
                scanf("%s",op);
                for(int i = 0;i<top;i++){
                    if(strcmp(op,c[i]) == 0){
                        gets(op);
                        int len = strlen(op);
                        int k = 1,j;
                        for(j = e[i].l;j<e[i].r && k < len;j++, k++)
                            s[j] = op[k];
                        if(j < e[i].r)
                            s[j] = '\0';
                        break;
                    }
                }
            }
        }
    }
}

自己wa的代码,求指出啊~

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <set>
#include <map>
using namespace std;
map<string,string> mp;
map<string,int>mp2;
map<string,int>mp3;

struct node{
    string name;
    int len;
    int id;
};
int main(){
    int T;scanf("%d",&T);

    while(T--){
        mp.clear();        mp2.clear(); mp3.clear();
        getchar();
        string a;
        getline(cin,a);
        int len = a.length();
        node no[10100]; int cnt  =0 ;
        for(int i=0;i<len;i++){
            if(a[i] == ' '){
                string tmp = "";
                int j = i+1;
                for(;j<len;j++){
                    if(a[j] == '[') break;
                }
                tmp = a.substr(i+1,j-i-1);
                no[cnt].name = tmp;
                int k = j+1;
                for(;k<len;k++)
                    if(a[k] == ']') break;
                tmp = a.substr(j+1,k-j-1);
                int tmpn = atoi(tmp.c_str());
                no[cnt].len = tmpn;
                no[cnt].id = cnt;
                mp2[no[cnt].name] = cnt;
                cnt++;
            }
        }
        while(1){
            string ord,num,str;
            cin>>ord;
            if(ord == "return"){
                cin>>num; break;
            }
            else if (ord == "gets"){
                cin>>num;
                getchar();
                getline(cin,str);
                string tmp  = str.substr(0,no[mp2[num]].len);
                mp[num] = tmp;
                if(str.length() >= no[mp2[num]].len)
                    mp3[num] = 1;
                else
                    mp3[num] = 0;
            }
            else if(ord == "cout"){
                cin>>num;
                if(mp[num] == ""){
                    cout<<endl;
                }
                else{
                    cout<<mp[num];
                    if(mp3[num]){
                            int cc= mp2[num] + 1;
                            for(int i = cc; i < cnt;i++){
                                if(mp[no[i].name] == "") break;
                                cout<<mp[no[i].name] ;
                                if(!mp3[mp[no[i].name]])
                                {
                                    continue;
                                }
                                else break;
                            }
                    }
                     cout<<endl;
                }
            }
        }
    }
}






I

占坑

J

阅读理解题,对于玩过炉石传说游戏的来说就是秒A了(果然ACMer要什么都懂。。)

#include<iostream>  
#include<cstdio>  
#include<cstring>  
#define mem(a,x) memset(a,x,sizeof(a))  
using namespace std;  
typedef long long ll;  
const int N = 100010;int a[5];  
char s[50];  
int main(){  
    int t;  
    scanf("%d",&t);  
    while(t--){  
        int n,hp; scanf("%d%d",&n,&hp);  
        getchar();  
        int C=0,M=0,O=0,B=0;  
        for(int i=0;i<n;i++){  
            gets(s);  
            if(s[0]=='C') C++;  
            if(s[0]=='M') M++;  
            if(s[0]=='O') O++;  
            if(s[0]=='B') B++;  
        }  
        int actO = O*(2+n-1+M*2);  
        int actB = B*(2+M*2);  
        if(actO + actB - hp >=0){  
            printf("Mrghllghghllghg!\n");  
        }  
        else  
            printf("Tell you a joke, the execution of Paladin.\n");  
    }  
    return 0;  
}  

K

字符串翻转,经典水题

#include<iostream>  
#include<cstdio>  
#include<cstring>  
#define mem(a,x) memset(a,x,sizeof(a))  
using namespace std;  
typedef long long ll;  
const int N = 100010;int a[5];  
char s[10100];  
int main(){  
    int t;  
    scanf("%d",&t);  
  
    getchar();  
    while(t--){  
        gets(s);  
        int len = strlen(s);  
        //cout<<s<<endl;  
        int l =0;  
        for(int i=0;i<=len;i++){  
            if(s[i] == ' ' || i == len){  
                for(int j=i-1;j>=l;j--) printf("%c",s[j]);  
                if(i != len)  
                    printf(" ");  
                else  
                    printf("\n");  
                l = i+1;  
                //cout<<" "<<i<<" "<<l<<endl;  
            }  
        }  
    }  
    return 0;  
}  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值