2020牛客寒假算法基础集训营1

整体难度codeforces div3水平(但我感觉挺难的)
标程题解:https://ac.nowcoder.com/discuss/364600?type=101&order=0&pos=1&page=1

A:honoka和格点三角形

这道题有点卡模吧,容斥定理的思想:

首先先算一条边平行于轴的情况:底边可以是1或2,(n-2)*(m-1)*m * 2 + (m-2) *m * (n-1) *2
再算一条边平行于y轴的情况:底边同样有两种情况:(n-1) *(m-2)*n * 2 + (n-2) *n * (m-1) *2

再减去两条边同时平行与x轴和y轴的情况:(m-2) * (n-1) * 4 + (n-2) * (m - 1)*4

但是我写的时候先求的上面的总的个数,减去了下面的重复的,由于同余定理用于减法时会出现负数的情况;就wa了,应该把式子合并起来在mod p;中间每一步都要mod p哦;

AC代码:

#include <bits/stdc++.h>
 
using namespace std;
typedef long long ll;
const int N=100001;
const int mod=1e9+7;
int main()
{
    ll n, m;
    cin >>n>>m;
//  ll a=(n-2)%mod*(m-1)%mod*m%mod*2%mod;
//  ll b=(m-2)%mod*m%mod*(n-1)%mod*2%mod;
//  ll c=(m-2)%mod*n%mod*(n-1)%mod*2%mod;
//  ll d=(n-2)%mod*n%mod*(m-1)%mod*2%mod;
//  cout <<a<<" "<<b<<" "<<c<<" "<<d<<endl;
//  cout <<((a+b)%mod+(c+d)%mod)%mod-(m-2)*(n-1)%mod*4%mod-(n-2)*(m-1)%mod*4%mod<<endl;
//  cout <<(a+b)%mod+(c+d)%mod<<endl;
//  cout <<(m-2)*(n-1)%mod*4%mod+(n-2)*(m-1)%mod*4%mod<<endl;
    cout <<((m-2)%mod*(m-2)%mod*(n-1)%mod*2%mod+(n-2)%mod*(n-2)%mod*(m-1)%mod*2%mod+m*(m-1)%mod*(n-2)*2%mod+n*(n-1)%mod*(m-2)%mod*2%mod)%mod<<endl;
}

.

E.rin和快速迭代E

质因子分解,求出约数个数,步步迭代即可;
AC代码:

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N=100001;
const int mod=1e9+7;
ll divide(ll x)
{
	ll ans=1;
	
    for (ll i = 2; i <= x / i; i ++ )
        if (x % i == 0)
        {
        	ll sum=0;
            while (x % i == 0) x /= i, sum ++ ;
            ans*=sum+1;
            //cout << i << ' ' << s << endl;
        }
    if (x > 1) ans*=2;
    
    return ans;
}
int main()
{
	ll n;
	cin >>n;
	int cot=0;
	while(1)
	{
		
		n=divide(n);
		cot++;
		if(n==2) break;
	}
	cout <<cot<<endl;
}

.

G.eli和字符串

记录每个字符出现的位置,然后暴力枚举不断更新最小值即可;

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N=100001;
const int mod=1e9+7;
vector<int> v[200001];
int main()
{
	int n,k;
	cin >>n>>k;
	string s;
	cin >>s;
	if(k==1)
	{
		cout <<1<<endl;
		return 0;
	}
	for(int i=0;i<n;i++)
	{
		char c=s[i];
		v[c].push_back(i);
	}	
	int minn=99999999;
	for(int i='a';i<='z';i++)
	{
		if(v[i].size()<k) continue;
		for(int j=k-1;j<v[i].size();j++)
		{
			minn=min(minn,v[i][j]-v[i][j-(k-1)]+1);
		}
	}
	if(minn==99999999) cout <<-1<<endl;
	else cout <<minn<<endl;
}

.

H.nozomi和字符串

此题属于寝室大佬指点之作,算一下整个字符串的前缀和,然后比如长度为L区间内的数字和为x,那么一定有x个1,L-x个0;
然后二分这个最大长度(0~n),对于每一个mid,就暴力枚举看当前位置 i 到 i + mid中min(x,mid-x)是否小于等于k;

注意二分的临界点,以及暴力枚举的临界点即可;

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N=200001;
const int mod=1e9+7;
int a[N];
int n,k;
bool check(int x)
{
	for(int i=x-1;i<n;i++)
	{
		int aa=a[i]-a[i-x],bb=x-a[i]+a[i-x];
		if(i-x<0) aa= a[i],bb=x-a[i];
		if(min(aa,bb)<=k) 
		{
			return true;
		}
	}
	return false;
}
int main()
{
	
	cin >>n>>k;
	string s;
	cin >>s;
	a[0]=s[0]-'0';
	for(int i=1;i<n;i++)
	{
		a[i]=s[i]-'0'+a[i-1];
	}
	int l=0,r=n,mid;
	while(l<r)
	{
		mid=l+r+1>>1;
		if(check(mid)) l=mid;
		else r=mid-1;
	}
	cout <<l<<endl;
	
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值