寒假牛客比赛20200204补题

目录

A

题意

honoka最近在研究三角形计数问题。
她认为,满足以下三个条件的三角形是“好三角形”。
1.三角形的三个顶点均为格点,即横坐标和纵坐标均为整数。
2.三角形的面积为。
3.三角形至少有一条边和 xxx 轴或 yyy 轴平行。
honoka想知道,在平面中选取一个大小为 n∗mn*mn∗m 的矩形格点阵,可以找到多少个不同的“好三角形”?
由于答案可能过大,请对 100000000710000000071000000007 取模。

思路

分成两种情况一种是两条边和坐标轴平行,另一种是只有一条边和坐标轴平行
在这里插入图片描述
第一种情况就是橙色的第一张,一定是12或者是21的情况对于一个12的矩形中含有四个不同的三角形,所以是、4((m-2)(n-1)+(m-1)(n-2)
第二种情况
①对于底边为2,高为1的情况:
若底边和x轴平行,那么底边横向移动(指x轴水平移动,下同)有 n-2 种可能,“对点”(指底边相对的点)的某一面选择有 n-2 种可能(某一面选择,指的是底边固定的情况,对点在一条直线上移动所做出的选择),而底边纵向移动有 m种情况,其中有 (m-2)种情况对点可以选择两个面,2种情况对点只能选择一个面(当底边移动到格点阵边界的时候)。因此纵向移动折合为 2*(m-2)+2,即2*(m-1)
以上可计算为2*(m-1)(n-2)(n-2)
若底边和y轴平行,同理可推出 2*(n-1)(m-2)(m-2)
②对于底边为1,高为2的情况,推理方法和上面类似,请选手们自行推理。
代码与思路不一样
代码 ans=(m−2)∗m∗(n−1)∗2+(n−2)∗n∗(m−1)∗2+(n−1)∗(m−2)∗(n−2)∗2+(m−1)∗(n−2)∗(m−2)∗2

#include <iostream>
#define IO ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
using namespace std;
typedef long long ll;
const int MOD = 1000000007;

ll M(ll x, ll y) { return ((x % MOD) * (y % MOD)) % MOD; }

int main()
{
    IO;
    ll n, m;
    cin >> n >> m;
    ll ans = 0;
    ans = (M(M(m - 2, m), M(2, n - 1)) + M(M(n - 2, n), M(2, m - 1)) + M(M(n - 1, m - 2), M(n - 2, 2)) + M(M(m - 1, n - 2), M(m - 2, 2))) % MOD;
    cout << ans << endl;
    return 0;
}

B

题意

给你一个n为音符的个数,每一个音符有x%的概率的a分,1-x%的概率得b分求得分的数学期望

思路

期望就是 nax%+nb(1-x%)

代码

#include<iostream>
#include<iomanip>
using namespace std;
int main()
{
	double n,x,a,b;
	cin>>n>>x>>a>>b;
	double sum;
	sum=n*a*(x/100)+n*b*(1-x/100);
	cout<<fixed<<setprecision(2)<<sum<<endl;
	return 0;
}

D

题意

n碗米饭 第1碗编号为1,2为2,n为n,拿走了 n-1碗米fan 告诉你拿走的编号 问你剩下了哪wan

思路

标记数组 将拿走的号都变成0输出1的就可以了

代码

#include<iostream>
#include<cstring>
using namespace std;
int main()
{
	int a[100010];
	int n;
	int temp;
	memset(a,1,sizeof a);
	cin>>n;
	for(int i=1;i<=n-1;i++)
	{
		cin>>temp;
		a[temp]=0;
	}
	for(int i=1;i<=n;i++)
	{
		if(a[i])
		 {
		 	cout<<i<<endl;
		 	break;
		 }
	}
	return 0;
}

E

题意

设f(x)为x因子的个数,比如f(12)=6,f(6)=4,f(4)=3,f(3)=2,求给你一个n,一直这样分 分到f()=2,所需要的的步数,例如 12 就是4

思路

暴力,题目怎么说你怎么做

代码

#include<iostream> 
#include<cmath>
using namespace std;
typedef long long ll;
ll f(ll n)
{
	ll sum=0;
	for(ll i=1;i<=sqrt(n*1.0);i++)
	 {
	 	if(n%i==0)
	 	{
	 		if(i*i==n)
	 		 sum++;
	 		else
	 		 sum+=2;
	 	}
	 }
	 return sum;
}
int main()
{
   ll n;
   cin>>n;
   int sum=0;
   while(n!=2)
   {
   	sum++;
   	n=f(n);
   }
   cout<<sum<<endl;
   
}

G

题意

给一个长度为n的全都是由小写字母组成的字符串,然后给你一个k ,求出现k 个相同字母的最短子串

思路

暴力,记录所有字母出现的次数以及每次出现的位置,然后分别暴力求解 每个字母再出现的所有次数里 截取k次,然后更新最小值

代码

#include<iostream>
#include<cstring>
#include<cstring> 
using namespace std;
struct node
{
    int trace[200010],in=1;
}sum[30];
int main()
{
	int n,k;
	string s;
	cin>>n>>k;
	cin>>s;
	for(int i=0;i<n;i++)
	{
		sum[s[i]-'a'].trace[sum[s[i]-'a'].in++]=i;
	}
	int ans=100000010;
	for(int i=0;i<26;i++)
	 for(int j=1;j<=sum[i].in-k;j++)//j是截取k次的头 所以最大也就是in-k
	  ans=min(ans,sum[i].trace[j+k-1]-sum[i].trace[j]+1);// j到 j+k 减1 才是k个数,求区间长度也是 b-a加1
	if(ans==100000010) 
	cout<<"-1"<<endl;
	else
	 cout<<ans<<endl;
	return 0;
}

H

题意

给你n为字符串的长度,然后输入字符串,全都是由01组成的,你有一种处理就是要么就是把0变成1,要么就是把1变成0,最多能处理k次,k次不一定全都要用完,问你处理出来的全都是由0或1组成的最长子串的长度

思路

如果是把1转换成0如果s[i]是1,先把次数用完,求出长度,如果次数用完了,看L指向如果指向的是a 就 l 加加r加加,这样是为了将一次转换次数用给下面的元素,如果是b就一直l 加加,一直加到l 指向的是a,如果是s【i】是0R就加加,不管怎样 R的指向都是和i 同步的,详细看注释

代码

#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
string s;
int n,k;
int deal(char a,char a1)//将a变成a1
{
	int L=0,R=0,change=0;
	int ans=1;
	for(int i=0;i<n;i++)
	{
		if(s[i]==a)
		 {
		 	if(change<k)
		 	 {
		 	 	R++;
		 	 	change++;
		 	 }//先求出来将转换次数用完的长度
			else
			{
				while(L<=R&&s[L]!=a)L++;//如果L指向a1 l加加,否则连不起来加到遇到a 
				R++;
				L++;//遇到a 了就都加1这样就满足了挪用了一次转换次数,都加1就相当于把之前
				//转换过的用成了转换别的a ,这样就其实就枚举了所有的转换次数 
			} 
		 }
		 else
		  R++;//如果是a1右边界就加加 
		 ans=max(ans,R-L);
	}
	return ans;
} 
int main()
{
    cin>>n>>k;
	cin>>s;
	cout<<max(deal('1','0'),deal('0','1'))<<endl;
	return 0;	
}



发布了8 篇原创文章 · 获赞 0 · 访问量 114

猜你喜欢

转载自blog.csdn.net/xgx984826498/article/details/104181852
今日推荐