B.https://ac.nowcoder.com/acm/contest/42400/B
题目大意,就是选取两个合法矩形,求总方案数为多少。
思路:可以很巧妙的转化一下问题,选取两个矩形,本质上就是在x和y轴各选四个点,外侧两个点可以认为就是大矩形的顶点,内部两个点认为是小矩形的的顶点,
则总方案数为C(n+1,4) * C(m+1,4),组合数直接求解即可.
思路转换很妙,记录一下。完整代码如下:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e5+10,mod=1e9+7;
int fac[N],infac[N];
int qmi(int a,int k)
{
int ans=1;
while(k)
{
if(k&1) ans=ans*a%mod;
a=a*a%mod;
k>>=1;
}
return ans;
}
void init()
{
fac[0]=1;infac[0]=1;
for(int i=1;i<N;i++) fac[i]=fac[i-1]*i%mod;
for(int i=1;i<N;i++) infac[i]=infac[i-1]*qmi(i,mod-2)%mod;
}
int C(int a,int b)
{
if(a<b) return 0;
return ((fac[a]*infac[b]%mod)*infac[a-b])%mod;
}
signed main()
{
init();
int t;
cin>>t;
while(t--)
{
int n,m;
cin>>n>>m;
cout<<C(n+1,4)*C(m+1,4)%mod<<endl;
}
return 0;
}
M.https://ac.nowcoder.com/acm/contest/42400/M
题目大意,给定一个字符串,多次询问s[L,R]这一段字串是否为该字符串的循环节。提到循环节,很容易想到KMP, 因为我们可以根据ne数组来求最小循环节,但我写到这里卡住了,发现还需要用到字符串哈希,后面看了题解,里面给出了一个结论:假设最小循环节长为len, 则s[L,R]为循环节的条件为 (L-1)%len==0 && R%len==0 && n%(R-L+1)==0 ,具体证明没有给出,如有大佬证明了可以告诉我呀!(我就先当结论记住)此方法时间复杂度为O(n).
另外,本题还能用字符串hash来做,暴力的判断字串是否为循环节,时间复杂度为O(logn*n),也可以通过此题。
KMP代码:
#include<bits/stdc++.h>
using namespace std;
#define ios std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int N=1e6+10;
string s;
int ne[N];
int n,m;
void get_next()
{
for(int i=2,j=0;i<=n;i++){
while(j&&s[i]!=s[j+1]) j=ne[j];
if(s[i]==s[j+1]) j++;
ne[i]=j;
}
}
signed main()
{
//cin>>n>>m;
scanf("%d%d",&n,&m);
cin>>s;
s=" "+s;
get_next();
while(m--)
{
int l,r;
//cin>>l>>r;
scanf("%d%d",&l,&r);
l++; r++;
int len=n-ne[n];
//if(l==1&&r==n) printf("YES\n");
if((l-1)%len==0&&r%len==0&&n%(r-l+1)==0) printf("YES\n");
else printf("NO\n");
}
return 0;
}
字符串hash:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef unsigned long long ull;
const int N = 1e6 + 5, P = 131;
int n, m;
char s[N];
ull p[N], h[N];
bool st[N];
ull get(int l,int r) {
return h[r] - h[l - 1] * p[r - l + 1];
}
void check(int x) {
for (int i = 1; i <= n; i += x) {
if (get(i, i + x - 1) != get(1, x)) return ;
}
st[x] = true;
}
int main() {
scanf("%d%d", &n, &m);
scanf("%s", s + 1);
p[0] = 1;
for (int i = 1; i <= n; i++) {
p[i] = p[i - 1] * P;
h[i] = h[i - 1] * P + s[i];
}
for (int i = 1; i <= n / i; i++) {
if (n % i == 0) {
check(i);
check(n / i);
}
}
while (m--) {
int l, r;
scanf("%d%d", &l, &r);
l++, r++;
if (st[r - l + 1] && get(1, r - l + 1) == get(l, r)) puts("YES");
else puts("NO");
}
return 0;
}