整体难度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;
}