21级爪哇程序设计新生赛(一) 题解

A 小爪的金铲铲(签到)

在这里插入图片描述

怎么说呢,前面几段废话是林建诚师兄费尽心思找的,纯粹是用来迷惑大家的。真正有用的只有最后一段话。 那我们可以根据题意写几个例子,可以发现答案都是3的n-1次方。找到规律就可以直接写出来程序了

#include<iostream> 
#include<cstdio> 
#include<algorithm> 
#include<cstring>
using namespace std;
int main()
{
  int n;
  while(cin>>n)
  {
    long long sum=1;
    n--;
    for (int i=1;i<=n;i++) sum*=3;
    cout<<sum<<endl;
  }
  return 0;
}

B 小爪查单词(字符串)

在这里插入图片描述
因为不分大小写,输入之后为了方便可以将所有的大写都变成小写,将每个单词拎出来,然后一个一个单词的判断就行了。

#include<iostream> 
#include<cstdio> 
#include<algorithm> 
#include<cstring>
#include<string>
#include<cstdlib>
using namespace std;
int main()
{
  string s1,s2,s3="";
  getline(cin,s1);
  getline(cin,s2);
  int len=s1.length();
  for (int i=0;i<len;i++) 
	  if (s1[i]<='Z' && s1[i]>='A') s1[i]+=-'A'+'a';
  int res=0,f=-1;
  for (int j=0;j<s2.length();j++)
  {
	  char c=s2[j];
	  if (c<='Z' && c>='A') c+=-'A'+'a';
	  if (c!=' ') s3+=c;
	  else
	  {
		  if (s3.length()==len)
		  {
			  bool flag=true;
			  for (int i=0;i<len;i++) 
				  if (s1[i]!=s3[i])
				  {
					  flag=false;
					  break;
				  }
			   if (flag)
			   {
				   if (res==0) f=j-s3.length();
				   res++;
			   }
		  }
		  s3="";
	  }
  }
  if (s3.length()==len)
  {
	  bool flag=true;
	  for (int i=0;i<len;i++) 
		  if (s1[i]!=s3[i])
		  {
			  flag=false;
			  break;
		  }
		  if (flag)
		  {
			  if (res==0) f=s2.length()-s3.length();
			  res++;
		  }
  }
  if (res!=0) cout<<res<<" ";
  cout<<f;
  return 0;
}

C 小爪的数学题(数学)

在这里插入图片描述
纯纯的计算题,算出平均数然后求方差即可。同时统计出最大和最小值。注意细节就行,没啥好说的

#include<iostream> 
#include<cstdio> 
#include<algorithm> 
#include<cstring>
#include<string>
#include<cstdlib>
using namespace std;
double a[1005];
int main()
{
  int T;
  cin>>T;
  while(T--)
  {
	  int n;
	  cin>>n;
	  double s=0;
	  for (int i=0;i<n;i++)
	  {
		  cin>>a[i];
		  s+=a[i];
	  }
	  if (n==1)
	  {
		  cout<<0<<" "<<0<<endl;
		  continue;
	  }
	  s/=(double)n;
	  double maxa=a[0],mina=a[0];
	  double res=(a[0]-s)*(a[0]-s);
	  for (int i=1;i<n;i++)
	  {
		  maxa=max(a[i],maxa);
		  mina=min(a[i],mina);
		  res+=(a[i]-s)*(a[i]-s);
	  }
	  res/=(double)n;
	  printf("%.lf %.3lf\n",maxa-mina,res);
  }
  return 0;
}

D 小爪的查询(easy version)(前缀和)

在这里插入图片描述
前缀和思想,前缀和是指某序列的前n项和,可以把它理解为数学上的数列的前n项和,a0=0,Sn=a1+a2+…+an,a2+a3+a4=S4-S1,a1+a2+a3=S3-S0

#include <iostream>
using namespace std;
const int N=1e5+5;
int n, m;
long long a[N],s[N];
int main()
{
    scanf("%d%d", &n, &m);
    for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
    for (int i=1;i<=n;i++) s[i]=s[i-1]+a[i]; 
    while (m--)
    {
        int l,r;
        scanf("%d%d", &l,&r);
        printf("%lld\n",s[r]-s[l-1]);
    }
    return 0;
}

E 小爪的查询(hard version)(st表模板)

在这里插入图片描述
倍增,RMQ算法模板题

#include<iostream>
#include<cstdio> 
#include<cmath>
#include<algorithm>
using namespace std;
int f[100001][40],x,len;
int main()
{
	int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {	
		int a;
        cin>>a;
        f[i][0]=a;
    }
    int p=(int)(log(n)/log(2));
    for(int j=1;j<=p;j++)
        for (int i=1;i<=n-(1<<j)+1;i++)
    		f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
    for(int i=1;i<=m;i++) 
    {
		int l,r;
        scanf("%d%d",&l,&r);
  		p=(int)(log(r-l+1)/log(2));
        printf("%d\n",max(f[l][p],f[r-(1<<p)+1][p]));
    }
    return 0;
}

F 小爪的工资管理(线段树)

在这里插入图片描述
也是林建诚师兄找的题
线段树

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
using namespace std;
const int maxn = 4e5 + 5;
const int maxn2 = 1e5 + 5;
int p;
struct node {
	long long int val = 0;
	long long int add = 0;//记录要加的数字
	long long int add2 = 1;//记录要乘的数字
};
node counts[maxn];
int numbers[maxn2];
void pushdown(int l, int r, int n)
{
	int mid = (l + r) / 2;
	int left = 2 * n + 1;
	int right = 2 * n + 2;
	counts[left].val = (counts[left].val * counts[n].add2 + (mid - l + 1) * counts[n].add) % p;//优先计算乘法counts[root*2].val=(counts[root*2].val*counts[root].mul+counts[root].add*(本区间长度))%p
	counts[right].val = (counts[right].val * counts[n].add2 + (r - mid) * counts[n].add) % p;
	counts[left].add2 = (counts[left].add2 * counts[n].add2) % p;
	counts[right].add2 = (counts[right].add2 * counts[n].add2) % p;
	counts[left].add = (counts[left].add * counts[n].add2 + counts[n].add) % p;
	counts[right].add = (counts[right].add * counts[n].add2 + counts[n].add) % p;
	counts[n].add2 = 1;
	counts[n].add = 0;
	return;
}
void build(int s, int e, int n)
{
	if (s == e)
	{
		counts[n].val = numbers[s];
		return;
	}
	int mid = (s + e) / 2;
	int left = n * 2 + 1;
	int right = n * 2 + 2;
	build(s, mid, left);//构建左子树
	build(mid + 1, e, right);//构建右子树
	counts[n].val = (counts[left].val + counts[right].val) % p;//左区间+右区间
}
void update_add(int s, int e, int L, int R, int v, int n)
{
	if (L <= s && R >= e)
	{
		counts[n].val = (counts[n].val + (e - s + 1) * v) % p;
		counts[n].add = (counts[n].add + v) % p;
		return;
	}
	int mid = (s + e) / 2;
	int left = 2 * n + 1;
	int right = 2 * n + 2;
	pushdown(s, e, n);
	if (L <= mid)
	{
		update_add(s, mid, L, R, v, left);//更新左区间
	}
	if (R > mid)
	{
		update_add(mid + 1, e, L, R, v, right);//更新右区间
	}
	counts[n].val = (counts[left].val + counts[right].val) % p;
}
void update_mu(int s, int e, int L, int R, int v, int n)
{
	if (L <= s && R >= e)
	{
		counts[n].val = (counts[n].val * v) % p;
		counts[n].add2 = (counts[n].add2 * v) % p;
		counts[n].add = (counts[n].add * v) % p;
		return;
	}
	int mid = (s + e) / 2;
	int left = 2 * n + 1;
	int right = 2 * n + 2;
	pushdown(s, e, n);//懒标记
	if (L <= mid)
	{
		update_mu(s, mid, L, R, v, left);
	}
	if (R > mid)
	{
		update_mu(mid + 1, e, L, R, v, right);
	}
	counts[n].val = (counts[left].val + counts[right].val) % p;
}
long long int query(int s, int e, int L, int R, int n)
{
	if (L <= s && R >= e)
	{
		return counts[n].val;
	}
	int mid = (s + e) / 2;
	int left = 2 * n + 1;
	int right = 2 * n + 2;
	pushdown(s, e, n);
	long long int sum = 0;
	if (L <= mid)
		sum = (sum + query(s, mid, L, R, left)) % p;
	if (R > mid)
		sum = (sum + query(mid + 1, e, L, R, right)) % p;
	return sum % p;
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int n, m;
	cin >> n >> m >> p;
	for (int i = 0; i < n; i++)
		cin >> numbers[i];
	build(0, n - 1, 0);
	while (m--)
	{
		int com;
		cin >> com;
		if (com == 1)
		{
			int x, y, k;
			cin >> x >> y >> k;
			x--, y--;
			update_mu(0, n - 1, x, y, k, 0);
		}
		else if (com == 2)
		{
			int x, y, k;
			cin >> x >> y >> k;
			x--, y--;
			update_add(0, n - 1, x, y, k, 0);
		}
		else
		{
			int x, y;
			cin >> x >> y;
			x--, y--;
			cout << query(0, n - 1, x, y, 0) << endl;
		}
	}
}

G 小爪打怪(思维)

在这里插入图片描述
从前往后计算每次删除操作后的操作数,再从后往前计算从当前位置往后删需要的操作数,然后枚举使用魔法后的操作数,求最小即可。

#include<iostream> 
#include<cstdio> 
#include<algorithm> 
#include<cstring>
#include<string>
#include<cstdlib>
using namespace std;
long long a[1000005],b[1000005];
long long p[1000005],q[1000005];
int main()
{
	int n;
	cin>>n;
	for (int i=1;i<=n;i++)
	{
		cin>>a[i];
		b[i]=a[i];
	}
	for (int i=1;i<=n;i++)
	{
		if (a[i]>0)
		{
			p[i]=p[i-1]+a[i];
			a[i+1]-=a[i];
			a[i+2]-=a[i];
		}else p[i]=p[i-1];
	}
	for (int i=n;i>=1;i--)
	{
		if (b[i]>0)
		{
			q[i]=q[i+1]+b[i];
			if (i-1>=0)b[i-1]-=b[i];
			if (i-2>=0)b[i-2]-=b[i];
		}else q[i]=q[i+1];
	}
	long long res=p[n];
	for (int i=1;i<=n;i++) res=min(res,p[i-1]+q[i+2]);
	cout<<res<<endl;
	return 0;
}

H 小爪的矩形(签到题)

在这里插入图片描述
签到题,如果有两根一样就看看第三根能不能分成两根一样的,如果不能组成一个矩形,那么就看看其中一根能否分成另外两根

#include<iostream> 
#include<cstdio> 
#include<algorithm> 
#include<cstring>
#include<string>
#include<cstdlib>
using namespace std;
int main()
{
	int a,b,c,T;
	cin>>T;
	while(T--)
	{
		cin>>a>>b>>c;
		if ((a==b && c%2==0) || (a==c&& b%2==0) || (b==c && a%2==0)) cout<<"YES"<<endl;
		else if (a==b+c || b==a+c || c==a+b) cout<<"YES"<<endl;
		else cout<<"NO"<<endl;
	}
	return 0;
}

I 小爪的出行(思维)

在这里插入图片描述
只需要将总时间加起来,然后看看能否整除2即可。

#include<iostream> 
#include<cstdio> 
#include<algorithm> 
#include<cstring>
#include<string>
#include<cstdlib>
using namespace std;
int main()
{
	long long a,b,c,T;
	cin>>T;
	while(T--)
	{
		cin>>a>>b>>c;
		long long t=a+b*2+c*3;
		t%=2;
		cout<<t<<endl;
	}
	return 0;
}

J 小爪的庆生(动态规划)

在这里插入图片描述
动态规划
将删除路标变成建设路标,这样删除最多k个路标就变成了建设最少n-k个路标。
dp[i][j]表示为到第i个坐标时有j个路牌的时间最小值。而状态转移方程if (j-1<=m) dp[i][j]=min(dp[i][j],dp[m][j-1]+(w[i]-w[m])*v[m]);为枚举从1到i个路标数j然后再枚举从1到i-1的坐标m,然后看看是坐标为m有j-1个路标时的最小值加上从m到i的时间与dp[i][j]谁更小,记录dp[i][j]的最小值。最后只需看看坐标为l路标数为n到n-k里最小值是多少即可。

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
using namespace std;
typedef long long ll;
typedef pair<int ,int> PII;
const int INF=0x3f3f3f35;
const int MOD=1e9+7;
const int N=505;
int dp[N][N];
int w[N],v[N];
int main()
{
	int n,l,k;
	cin>>n>>l>>k;
	for (int i=1;i<=n;i++) cin>>w[i];
	for (int i=1;i<=n;i++) cin>>v[i];
	for (int i=0;i<=n+1;i++)
		for (int j=0;j<=n+1;j++) dp[i][j]=INF;
	dp[1][1]=0;
	w[++n]=l;
	for (int i=2;i<=n;i++)
		for (int j=1;j<=i;j++)
			for (int m=1;m<i;m++)
				if (j-1<=m) dp[i][j]=min(dp[i][j],dp[m][j-1]+(w[i]-w[m])*v[m]);
	int res=INF;
	for (int i=0;i<=k;i++) res=min(res,dp[n][n-i]);
	cout<<res<<endl;
	return 0;
}

K 小爪去买瓜(动态规划)

在这里插入图片描述
dp[i]表示总重量为i时的方案数
状态转移方程:
if (j>=a[i])dp[j]=(dp[j]+dp[j-a[i]])%mod;
dp[j]=(dp[j]+dp[j-a[i]/2])%mod;

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
#include <vector>
#include <queue>
#include <set>
using namespace std;
typedef long long ll;
typedef pair<int ,int> PII;
const int INF=0x3f3f3f;
const int mod=1e9+7;
const int N=1e3+5;
int a[N];
ll dp[N];
bool f[N];
int main()
{
	int n,m;
	cin>>n>>m;
	for (int i=1;i<=n;i++) cin>>a[i];
	sort(a+1,a+1+n);
	dp[0]=1;
	for (int i=1;i<=n;i++)
	{
		for (int j=m;j>=a[i]/2;j--) 
		{
			if (j>=a[i])dp[j]=(dp[j]+dp[j-a[i]])%mod;
			dp[j]=(dp[j]+dp[j-a[i]/2])%mod;
		}
	}
	for (int i=1;i<=m;i++) cout<<dp[i]<<" ";
	cout<<endl;
	return 0;
}

L 小爪的素数 (easy version)(判断素数)

在这里插入图片描述

直接根据定义判断素数

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <string>
using namespace std;
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		int n;
		cin>>n;
		string flag="YES";
		for (int i=2;i*i<=n;i++) 
			if (n%i==0)
			{
				flag="NO";
				break;
			}
		cout<<flag<<endl;
	}
	return 0;
}

小爪的素数(hard version)(快速判断素数)

在这里插入图片描述
数据较大就无法用定义的方法来解决问题了

快速判断素数
原理
大于等于5的素数与6的倍数相邻
证明
所有自然数可以用集合A = { 6n, 6n+1, 6n+2, 6n+3, 6n+4, 6n+5 }表示,其中 n >= 0,显然,子集B = {6n, 6n+2, 6n+3, 6n+4}内的元素都不是素数,所以只有6n+1和6n+5可能是素数,素数一定可以用6n+1和6n+5其中的一个形式表示,即大于等于5的素数与6的倍数相邻 。
因子判断
上面说到大于或等于5的素数一定可以用6n+1或者6n+5来表示,在判断一个数num是否是素数时,需要判断num是否有除1和自身之外的因子。这时只需要判断x是否是num的因子,其中1 < x <= int(sqrt(num)),而x的范围又可以用集合{ 6i, 6i+1, 6i+2, 6i+3, 6i+4, 6i+5 }表示。当num与6的倍数相邻时,num才可能是素数,因为num(奇数)和{6i, 6i+2, 6i+3, 6i+4}(偶数)互素,也就是{6i, 6i+2, 6i+3, 6i+4}不可能是num的因子,此时只需判断x = 6i+1和x = 6i+5是否是num的因子即可,如果都不是,则num是素数。

#include <iostream>
#include <cmath>
#include <cstdio>
#include <Windows.h>
using namespace std;
const int N=1e5+5;
int n, m;
long long a[N],s[N];
int isprime(const long long num) 
{
	unsigned long long i, half;
	
	if (num <= 1)
		return 0;
	if (num == 2 || num == 3)
		return 1;
	// 不和6的倍数相邻的数不是素数
	else if (num % 6 != 1 && num % 6 != 5)
		return 0;
		
	half = (unsigned int)sqrt((double)num);
	for (i = 5; i <= half; i += 6)
	{
		if (num % i == 0 || num % (i + 2) == 0)
			return 0;
	}
	return 1;
}
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		long long n;
		cin>>n;
		if (isprime(n)) cout<<"YES"<<endl;
		else cout<<"NO"<<endl;
	}
    return 0;
}

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值