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;
}