“浪潮杯”山东省第七届ACM大学生程序设计竞赛

写题解之前先吐槽一下这次训练的OJ,好像是叫什么“V4T”的OJ,超级难用。隔壁组提交之后一直卡在submitting,最后发现是不能有多余的空格,就是vs里面自动生成的那种空格是不行的。是真的毒瘤,搞了半个小时才弄好,后面我们又卡在了c题的提交上,一气之下直接跑到山东师范大学oj交的题目。不过还好的是之后队友给OJ负责人的邮箱发了个邮件说明了一下问题,很快就得到了回复和修改。之前卡在submitting的所有提交都过了。真的是很影响做题体验了。

A:水题,直接除一下向上取整

#include<bits/stdc++.h>
using namespace std;
int main(){
	double a,b;
	int t;
	cin>>t;
	while(t--)
	{
		cin>>a>>b;
		double c=a/b;
		int d=c;
		if(d==c)
		{
			cout<<d<<endl;
		}
		else cout<<d+1<<endl;
	}
	return 0;
}

B:斐波那契数列打个表,然后从大到小减一下就行了(这道题队友写的代码,看不懂的)

#include<bits/stdc++.h>
using namespace std;
long long fb[55];
long long  jl[1111111];
int zz;
int main(){
fb[0]=1;
fb[1]=2;
int js;
for( js=2;js;js++)
{
	if(fb[js-1]>=1000000001)
	break;
	fb[js]=fb[js-1]+fb[js-2];
}
	int t;
	cin>>t;
	long long n;
	while(t--)
	{
	    zz=0; 
	    scanf("%lld",&n);
	    long long aa=n;
	    int f1=0;
	    while(n)
	    {
	    	int pos=lower_bound(fb,fb+js,n)-fb;
	    	if(fb[pos]==n)
	    	{
	    		n-=fb[pos];
	    		jl[zz++]=fb[pos];
	    		break;
			}
	    	n-=fb[pos-1];
	    	jl[zz++]=fb[pos-1];
		}
		if(n!=0)
		printf("-1\n");
		else {
			printf("%lld=%lld",aa,jl[zz-1]);
			for(int i=zz-2;i>=0;i--)
			{
				printf("+%lld",jl[i]);
			}
			printf("\n");
		}
	}
	return 0;
}

C:听队友说是很水的一个最短路,spfa模板直接过

#include<bits/stdc++.h>
using namespace std;
const int N=22222;
const int inf=0x3f3f3f3f;
struct ndoe
{
    int u,v,w,next;
}e[N<<2];
int head[N<<2];
int dis[N],vis[N],pre[N];
int num;
int n,m;
void addedge(int u,int v,int w)
{
    e[num].v=v;
    e[num].w=w;
    e[num].next=head[u];
    head[u]=num++;
}
void spfa()
{
    memset(vis,0,sizeof(vis));
    memset(dis,inf,sizeof(dis));
    memset(pre,inf,sizeof(pre));
    dis[0]=0;
    vis[0]=1;
    pre[0]=-1;
    queue<int>q;
    q.push(0);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=head[u];i!=-1;i=e[i].next)
        {
            int v=e[i].v;
            if(dis[v]>dis[u]+e[i].w)
            {
                dis[v]=dis[u]+e[i].w;
                pre[v]=u;
                if(!vis[v])
                {
                    q.push(v);
                    vis[v]=1;
                }
            }
            else if(dis[v]==dis[u]+e[i].w)
            {
                pre[v]=min(pre[v],u);
            }
        }
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset(head,-1,sizeof(head));
        num=0;
        scanf("%d%d",&n,&m);
        int u,v,w;
        for(int i=0;i<m;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            addedge(u,v,w);
        }
        spfa();
        if(dis[n+1]==inf)
        {
            printf("-1\n");
            continue;
        }
        int t=n+1;
        int k;
        while(t!=0)
        {
            k=t;
            t=pre[t];
        }
        if(k==n+1)printf("0\n");
        else printf("%d\n",k);
    }
    return 0;
}

E:如果一个房间上下左右四个方向有且仅有一个'#',那么这个房间就是特殊房间,求特殊房间的个数。果断暴力啊。

#include<bits/stdc++.h>
using namespace std;
char ma[111][111];
bool check(int x,int y)
{
	if(ma[x][y]=='#')return 1;
	return 0;
}
int main(){
	int t;
	cin>>t;
	while(t--)
	{
	    int n,m;
	    cin>>n>>m;
	    memset(ma,0,sizeof(ma));
	    for(int i=1;i<=n;i++)
	    {
	    	for(int j=1;j<=m;j++)
	    	{
	    	    cin>>ma[i][j];
			}
		}
		int ans=0;
		for(int i=0;i<=n+1;i++)
		{
			for(int j=0;j<=m+1;j++)
			{
				if(ma[i][j]=='.'||ma[i][j]==0)
				{
					int zs=0;
					if(check(i+1,j))
					zs++;
					if(check(i,j+1))
					zs++;
					if(check(i-1,j))
					zs++;
					if(check(i,j-1))
					zs++;
					if(zs==1)
					ans++;
					//cout<<zs<<endl;
				}
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}

F:(赛后清题)题意是给你三种水果分别a,b,c个,让你进行全排列,其中第一种水果连续个数不能超过aa,第二种水果不能超过bb,第三种水果不能超过cc。让你求排列有多少种。

四维dp,dp[i][j][k][s]表示的意思是第一种水果使用i个,第二种水果使用j个,第三种水果使用k个,结尾为s(s=0,1,2)的排列有多少种。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
#define LL long long int
const int mod = 1000000007;
int T;
int a, b, c;
int aa, bb, cc;
LL dp[55][55][55][5];
int main()
{
	cin >> T;
	while (T--)
	{
		cin >> a >> b >> c >> aa >> bb >> cc;
		memset(dp, 0, sizeof(dp));
		for (int i = 0; i <= a; i++)
		{
			for (int j = 0; j <= b; j++)
			{
				for (int k = 0; k <= c; k++)
				{
					for (int s = 1; s <= min(a - i, aa); s++)
					{
						if (i == 0 && j == 0 && k == 0)
							dp[i + s][j][k][0] += 1;
						else
							dp[i + s][j][k][0] = (dp[i + s][j][k][0] + dp[i][j][k][1] + dp[i][j][k][2]) % mod;
					}
					for (int s = 1; s <= min(b - j, bb); s++)
					{
						if (i == 0 && j == 0 && k == 0)
							dp[i][j + s][k][1] = 1;
						else
							dp[i][j + s][k][1] = (dp[i][j][k][0] + dp[i][j + s][k][1] + dp[i][j][k][2]) % mod;
					}
					for (int s = 1; s <= min(c - k, cc); s++)
					{
						if (i == 0 && j == 0 && k == 0)
							dp[i][j][k + s][2] = 1;
						else
							dp[i][j][k + s][2] = (dp[i][j][k][0] + dp[i][j][k][1] + dp[i][j][k + s][2]) % mod;
					}
				}
			}
		}
		LL res = (dp[a][b][c][0] + dp[a][b][c][1] + dp[a][b][c][2]) % mod;
		cout << res << endl;
	}
	return 0;
}

G:题意就是给你n个石子,让你分成三堆,求出后手必胜(先手必败)的方案有多少种。

nim博弈嘛,就是求三堆异或和为0的情况有多少种,我们打表打出来前一百或者二百的情况数量以及相应的二进制表示。不难发现结果是有规律的。首先,奇数的肯定结果就为0,然后我们记录除了首位1以外其他1的个数,然后在一起以三进制的结果输出。

例如:110110

除了首位的1以外有三个1,结果就是111(三进制),即9+3+1=13

四个1就是1111,即27+9+3+1=40

跟1的位置没关系的

PS:隔壁队的想法是记录个数然后一直(*3+1),都是可以的。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<string>
#include<iomanip>
using namespace std;
#define LL long long int
int main()
{
	int T,n;
	cin>>T;
	while(T--)
	{
		cin>>n;
		if(n&1)
		{
			cout<<0<<endl;
			continue;
		}
		int res=0;
		while(n)
		{
			res+=n%2;
			n/=2;
		}
		if(res==1)
		{
			cout<<0<<endl;
			continue;
		}
		LL cmp=1;
		LL ans=0;
		for(int i=1;i<res;i++)
		{
			ans+=cmp;
			cmp*=3;
		}
		cout<<ans<<endl;
	}
	return 0;
}

J:炉石传说的题目,我日常没看懂,队友写的,据说是除了第一题以外最水的题目

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int T;
    char m[111];
    scanf("%d",&T);
    while(T--)
    {
        int n,h;
        scanf("%d%d",&n,&h);
        getchar();
        int al=0;
        int ax=0;
        int ay=0;
        for(int i=0;i<n;i++)
        {
        	gets(m);
        	if(m[0]=='M')ay++;
        	else if(m[0]=='B')al++;
        	else if(m[0]=='O')ax++;
		}
		h-=(al*2+al*ay*2+ax*(2+ay*2+n-1));
		if(h>0)printf("Tell you a joke, the execution of Paladin.\n");
		else printf("Mrghllghghllghg!\n");
    }
    return 0;
}


K:直接gets整个输入,然后遍历遇到空格时把之前的倒着输出就行了,最后把剩下的给输出。

#include<bits/stdc++.h>
using namespace std;
int main(){
	int t;
	char s[11111];
	cin>>t;
	getchar();
	while(t--)
	{
		gets(s);
		int l=0,r=-1;
		int le=strlen(s);
		for(int i=0;i<le;i++)
		{
			if(s[i]==' ')
			{
				for(int j=i-1;j>=l;j--)
				printf("%c",s[j]);
				printf(" ");
				l=i+1;
			}
		}
		if(l<le)
		{
			for(int i=le-1;i>=l;i--)
			printf("%c",s[i]);
		}
		printf("\n");
	}
	return 0;
}

这套题7题是稳银的,但是要8题快或者9题才能拿金。隔壁队最后又过了一道题应该是金牌区了。太强了太强了。客观来讲前面的六七道题都是水题,整套题做下来从难度来讲觉得内陆的省赛和江浙的省赛还是有点差距的。

猜你喜欢

转载自blog.csdn.net/b_r_e_a_d/article/details/80200036