2021年GDUT第11届腾讯杯新生程序设计竞赛(补题)

费话不多说,直接开始补题吧(主要也是没啥心情说了)

(题解没有代码,寄)


A 比比谁更大

 废话可跳过:在本次比赛A题的位置,一开始做直接写了求阶乘的递归函数,WA了一发。然后看到了数据范围:1e9(这么大的数据范围还写递归真是疯了)。然后注意到题目中给的“很妙的模数”,发现它并不是质数,然后把它质因数分解可写为3*7*11*13*17*19*103。看到这记得之前做过这样类似的题,好像是和103有关但是想不起来了,,,还是对取模运算掌握不熟练。

思路:999068070=3*7*11*13*17*19*103,最大的质因数为103,所以大于等于103的阶乘都是可以整除999068070,即取模后都为0。那么把数分为大于等于103和小于103两部分,大于等于103的部分直接用前面的结论,即都输出两数相等的情况;对于小于103的部分,直接暴力求解即可,我是写的递归函数求阶乘。(记得有几组特判!)

AC代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <stack>
#include <vector>
#include <map>
#include <queue>
#include <cstring>
#include <cmath>
#include <set>
#include <iterator>
#include <numeric>

using namespace std;

typedef long long ll;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define INF 0x3f3f3f3f
//判断是否需要开ll!!!
//判断是否需要初始化!!!
const int mod=999068070;
ll a,b;
int m[1000005];

ll func(ll a)
{
	if(a==0) return 1;
	else
	return func(a-1)*a%mod;
}

int main()
{
//	freopen("test.in","r",stdin);
    cin>>a>>b;
    m[0]=1;
    for(int i=1;i<=103;i++)
    {
    	m[i]=i*m[i-1]%mod;
	}
	if(a>=103&&b>=103)
	cout<<"There is no winner!"<<'\n';
	else if(a>=103&&b<103)
	cout<<"b is the winner!"<<'\n';
	else if(b>=103&&a<103)
	cout<<"a is the winner!"<<'\n';
	else
	{
		if(func(a)>func(b))
        cout<<"a is the winner!"<<'\n';
        else if(func(a)<func(b))
        cout<<"b is the winner!"<<'\n';
        else if(func(a)==func(b))
        cout<<"There is no winner!"<<'\n';
	}
    
	return 0;
}

B - 过生日

思路: 二维数组处理到第i个字符26个字母个数前缀和,二分查找满足条件的长度。

AC代码:

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define INF 0x3f3f3f3f
//判断是否需要开ll!!!
//判断是否需要初始化!!!
const int mod=1e9+7;
const int N=2e5+5;
int t,k,cnt[N][28],len;
string s;

bool check(int x)
{
	for(int i=x;i<=len;i++)
	{
		for(int j=0;j<26;j++)
		{
			if(cnt[i][j]-cnt[i-x][j]>=k) 
			return true;
		}
	}
	return false;
}

int main()
{
//	freopen("test.in","r",stdin);
//  freopen("output.in", "w", stdout);
    cin>>t;
    while(t--)
    {
    	memset(cnt,0,sizeof(cnt));
    	cin>>s>>k;
    	len=s.length();
    	s=" "+s;
    	for(int i=1;i<=len;i++)
    	{
    		for(int j=0;j<26;j++)
    		cnt[i][j]=cnt[i-1][j];
    		cnt[i][s[i]-'a']++;
		}
		int l=0,r=len;
		while(l<r)
		{
			int mid=(l+r)>>1;
			if(check(mid)) r=mid;
			else l=mid+1;
		}
		if(l==len&&!check(l)) cout<<"-1"<<'\n';
		else cout<<l<<'\n';
	}
	return 0;
}

os:二分用法很灵活

C hhgg爱Java

废话可跳过:一开始看题的时候没看懂直接跳了,然后后来看榜上这个题的AC数很多, 然后仔细看了看读懂了(我真fw)。这个题我是用结构体+数组做的,好像有同学是用map做的也可以。

思路:分清楚到底是根据哪个数排序,用flag判断是否有重复的字符串。

AC代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <stack>
#include <vector>
#include <map>
#include <queue>
#include <cstring>
#include <cmath>
#include <set>
#include <iterator>
#include <numeric>
 
using namespace std;
 
typedef long long ll;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define INF 0x3f3f3f3f
//判断是否需要开ll!!!
//判断是否需要初始化!!!
const int mod=1e9+7;
int n;
 
struct node
{
    int time,num;
    char c[105];
    bool flag;
} e[105];
 
bool cmp1(node a,node b)
{
    if(a.time<b.time) return true;
    else return false;
}
 
int main()
{
//  freopen("test.in","r",stdin);
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>e[i].c>>e[i].time;
        e[i].num=i;
        for(int j=1;j<i;j++)
        {
            if(strcmp(e[j].c,e[i].c)==0&&e[j].time<e[i].time)
            e[j].flag=true;
            if(strcmp(e[j].c,e[i].c)==0&&e[j].time>e[i].time)
            e[i].flag=true;
        }  
    }
    sort(e+1,e+1+n,cmp1);
    for(int i=1;i<=n;i++)
    {
        if(e[i].flag==false)
        cout<<e[i].num<<'\n';
    }
    return 0;
}

D - 机器人

思路: 数据范围很小,直接模拟。

AC代码:

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define INF 0x3f3f3f3f
//判断是否需要开ll!!!
//判断是否需要初始化!!!
const int mod=1e9+7;
const int N=13;
int n,k;
int a[N][N];

bool check()
{
    for(int i=1;i<=n;i++)
	{
        for(int j=1;j<=n;j++)
		{
            if((i-1)*n+j!=a[i][j])
			return 0;
        }
    }
    return 1;
}

void f(){
    int t=a[1][1];
    for(int i=2;i<=n;i++) a[1][i-1]=a[1][i];
    for(int i=2;i<=n;i++) a[i-1][n]=a[i][n];
    for(int i=n-1;i>=1;i--) a[n][i+1]=a[n][i];
    for(int i=n-1;i>=1;i--) a[i+1][1]=a[i][1];
    a[2][1]=t;
}

int main()
{
//	freopen("test.in","r",stdin);
//  freopen("output.in", "w", stdout);
    scanf("%d",&n);
    int flag=1;
    for(int i=1;i<=n;i++)
	{
        for(int j=1;j<=n;j++)
        scanf("%d",&a[i][j]);
    }
    for(int i=1;i<=100;i++)
	{
        f();
        if(check())
		{
            cout<<"YES";
			return 0;
        }
    }
    cout<<"NO";
	return 0;
}

os:模拟真的麻烦,但是模拟的能力很重要!

F osu!

思路

(1)我的思路:在文章中o,s,u的顺序是不一定的,我的做法是先遍历数每个s前o的数量,用数组存一下,作为每一个s的值,再一次遍历u,把每一个u前s的值相加。

AC代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <stack>
#include <vector>
#include <map>
#include <queue>
#include <cstring>
#include <cmath>
#include <set>
#include <iterator>
#include <numeric>
 
using namespace std;
 
typedef long long ll;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define INF 0x3f3f3f3f
//判断是否需要开ll!!!
//判断是否需要初始化!!!
const int mod=1e9+7;
string c;
int s;
int mp1[105],mp2[105];
 
int main()
{
//  freopen("test.in","r",stdin);
    cin>>s;
    cin>>c;
    int cnt=0;
    for(int i=0;i<s;i++)
    {
        if(c[i]=='o')
        {
            ++cnt;
        }
        if(c[i]=='s')
        mp1[i]=cnt;
    }
    for(int i=0;i<s;i++)
    {
        if(c[i]=='u')
        for(int j=0;j<=i;j++)
        {
            mp2[i]+=mp1[j];
        }
    }
    int sum=0;
    for(int i=0;i<s;i++)
    {
        sum+=mp2[i];
    }
    cout<<sum<<'\n';
    return 0;
}

(2)题解思路:对于每个s,对于答案的贡献是它左边的o的数量乘它右边u的数量,o和s的数量分别用前缀和和后缀和可以很轻松的O(n)预处理。(没有题解代码,将就看看我写的吧,不过这样想确实要好写许多)

AC代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <stack>
#include <vector>
#include <map>
#include <queue>
#include <cstring>
#include <cmath>
#include <set>
#include <iterator>
#include <numeric>

using namespace std;

typedef long long ll;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define INF 0x3f3f3f3f
//判断是否需要开ll!!!
//判断是否需要初始化!!!
const int mod=1e9+7;
string c;
int co[105],cu[105],cs[105];
int n,sum;

int main()
{
//	freopen("test.in","r",stdin);
    cin>>n;
    cin>>c;
	if(c[0]=='o')
	co[0]=1;
	for(int i=1;i<n;i++)
	{
		if(c[i]=='o')
		co[i]=co[i-1]+1;
		else
		co[i]=co[i-1];
	}
	for(int i=n-1;i>=0;i--)
	{
		if(c[i]=='u')
		cu[i]=cu[i+1]+1;
		else
		cu[i]=cu[i+1];
	}
	for(int i=0;i<n;i++)
	{
		if(c[i]=='s')
		cs[i]=co[i]*cu[i];
		sum+=cs[i];
	}
	cout<<sum<<'\n';
	return 0;
}

G 拼牛牛

废话可跳过: 做这个题的时候就是比赛后半段时间了,当时有点慌了,感觉是暴力可以过,但也没仔细想怎么暴力做,,,如果是高中的我可能就做出来了,现在连等比数列都忘了(fw)。事实证明暴力可以过的。

思路

(1)科学做法:函数收敛性相关 可以明显看出增长数字是一个等比数列,根据等比数列知道,从别人处得到的钱数为1*(k^0+k^1+……+k^(n-1)),求和为1*(1-k^n)/(1-k),根据极限可求得p每一个值时极限的n,因为k为一位小数,逐个计算即可,代码实现类似打表。

AC代码(没有代码,将就看看我写的吧):

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <stack>
#include <vector>
#include <map>
#include <queue>
#include <cstring>
#include <cmath>
#include <set>
#include <iterator>
#include <numeric>

using namespace std;

typedef long long ll;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define INF 0x3f3f3f3f
//判断是否需要开ll!!!
//判断是否需要初始化!!!
const int mod=1e9+7;
int t;
int n;
double k;

int main()
{
//	freopen("test.in","r",stdin);
    cin>>t;
    while(t--)
    {
    	cin>>n>>k;
    	if(k<=0.5&&n>=99)
    	cout<<"YES"<<'\n';
    	else if(k==0.6&&n>=98)
    	cout<<"YES"<<'\n';
    	else if(k==0.7&&n>=97)
    	cout<<"YES"<<'\n';
    	else if(k==0.8&&n>=96)
    	cout<<"YES"<<'\n';
    	else if(k==0.9&&n>=91)
    	cout<<"YES"<<'\n';
    	else
    	cout<<"NO"<<'\n';
	}
	return 0;
}

(2)暴力做法:就是自己写个求k的各个次方求和的程序,粗略估计范围,不过会有精度差距需注意(不推荐)。

I 史莱姆

 思路:这个思路就比较简单了,分裂到最后每个史莱姆的生命值一定是质数才无法分解,分解给出的n的质因数即可(注意n==1时的特判!)

AC代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <stack>
#include <vector>
#include <map>
#include <queue>
#include <cstring>
#include <cmath>
#include <set>
#include <iterator>
using namespace std;
typedef long long ll;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define maxn 10000005
#define INF 0x3f3f3f3f
const int mod=1e9+7;
//多组输入记得每次循环之前初始化(数组,栈,队列,某些变量)!!!
const int N=1000005;
int prime[N],m[N];
bool mark[N];
int tot;
 
 
 
int main()
{
    int i,j;
    tot=0;
    mark[0]=mark[1]=1;
    for(i=2;i<=100005;i++)
    {
        if(!mark[i])
        prime[++tot]=i;
        for(j=1;j<=tot;j++)
        {
            if(i*prime[j]>100005)
            break;
            mark[i*prime[j]]=1;
            if(i*prime[j]==0)
            break;
        }
    }
     
    int b,n;
    int cnt=0;
    scanf("%d",&n);
    if(n==1)
    cout<<"1"<<'\n';
    else
    {
        b=n;
    for(int i=1;i<=tot;i++)
    {
        if(b<prime[i])
        break;
        while(b%prime[i]==0)
        {
            m[++cnt]=prime[i];
            b=b/prime[i];
        }      
    }
    cout<<cnt<<'\n';
    }
     
     
    return 0;
}

L 歪脖子树下的灯

废话可跳过:一开始看的时候列了几个情况试图找规律,然后失败了。。。

思路: 

(1)二项分布:由于每次开关都不会相互影响,那么这题符合n次独立重复的伯努利试验。所以可以使用二项分布公式来计算,但是由于此题的特殊性,即所给p是状态改变的概率,改变奇数次则一定最后一次为亮,改变偶数次则一定为暗,故不能全取,只能取奇数项。(化简我和室友算了半个多小时才整出来。。。)

化简过程:

 AC代码(用化简的这个式子很好实现,也是自己写的,莫得答案代码):

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <stack>
#include <vector>
#include <map>
#include <queue>
#include <cstring>
#include <cmath>
#include <set>
#include <iterator>
#include <numeric>

using namespace std;

typedef long long ll;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define INF 0x3f3f3f3f
//判断是否需要开ll!!!
//判断是否需要初始化!!!
const int mod=1e9+7;
int t;
int n;
double p;

double pmod(double a,int b)
{
	double res=1;
	while(b)
    {
    	if(b%2==1)
    	res=res*a;
    	b/=2;
    	a=a*a;
	}
	return res;
}

int main()
{
//	freopen("test.in","r",stdin);
    cin>>t;
    while(t--)
    {
    	scanf("%d",&n);
    	scanf("%lf",&p);
    	double a=pmod(1-2*p,n);
    	double s=(1-a)/2;
    	printf("%.6lf\n",s);
	}
	return 0;
}

(2)递推做法:设f [ i ]为第i次拉后,灯为亮着的概率。已知f [ 0 ] = 0,求f [ i ]。
f [ i ] = (1 - p)  * f [ i - 1 ] + p * (1 - f [ i - 1 ]) = (1 - 2 * p) * f [ i - 1 ] + p,直接带公式算即可。(公式怎么出来的?代几组试试,找规律吧)

AC代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <stack>
#include <vector>
#include <map>
#include <queue>
#include <cstring>
#include <cmath>
#include <set>
#include <iterator>
#include <numeric>

using namespace std;

typedef long long ll;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define INF 0x3f3f3f3f
//判断是否需要开ll!!!
//判断是否需要初始化!!!
const int mod=1e9+7;
const int N=105;
int t;
int n;
double p;
double f[N];

int main()
{
//	freopen("test.in","r",stdin);
    cin>>t;
    while(t--)
    {
    	scanf("%d",&n);
    	scanf("%lf",&p);
    	f[0]=0;
    	for(int i=1;i<=n;i++)
    	{
    		f[i]=(1-2*p)*f[i-1]+p;
		}
		printf("%.6lf\n",f[n]);
	}
	return 0;
}

这个补题拖了好久啊

若有错误请指教orzorz

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值