A | 魔法部落 |
---|---|
B | 圆盘题解 |
C | 棋盘行走 |
D | 走方格题解 |
A
本题使用等比数列求和公式即可得到以下答案
a
n
s
=
(
3
n
−
1
)
2
ans=\frac{(3^n-1)}{2}
ans=2(3n−1)
之后逆元即可在log的复杂度内解决本题。
一个数在摸
P
P
P意义下的逆元怎么求:
b^(p-2)%p
#include<iostream>
#include<cstdio>
using namespace std;
long long n;
int main()
{
scanf("%lld", &n);
long long x=3;
long long sum=1;
while(n!=0){
if(n&1)
sum=sum*x%1000000007;
x=x*x%1000000007;
n>>=1;
}
sum=3*(1-sum)*1000000008/(-2)%1000000007;
printf("%lld", (sum+1)%1000000007);
return 0;
}
B
这里用最小表示法来做。可以在
O
(
n
2
)
O(n^2)
O(n2)求出所有最小表示,然后可以
O
(
n
)
O(n)
O(n)统计有多少对相同。
最小表示模板
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
int n, m, p;
int a[510][1010], b[10010];
int MRA[10010];
int mra(int t[])
{
int i=1, j=2, k;
while(i<=2*m&&j<=2*m)
{
for(k=0; k<=2*m&&t[i+k]==t[j+k]; k++);
if(k==m*2)
break;
if(t[i+k]<t[j+k])
{
i+=k+1;
if(i==j)
i++;
}
else
{
j+=k+1;
if(i==j)
j++;
}
}
return min(i, j);
}
int main()
{
scanf("%d%d%d", &n, &m, &p);
for(register int i=1; i<=n; ++i)
{
for(register int j=1; j<=m; ++j)
scanf("%d", &b[j]);
sort(b+1, b+1+m);
for(int j=1; j<m; j++)
{
a[i][j]=abs(b[j+1]-b[j]);
a[i][j+m]=a[i][j];
}
a[i][m]=a[i][2*m]=b[1]+p-b[m];
MRA[i]=mra(a[i]);
}
register int sum=0;
for(register int i=1; i<=n; ++i)
for(register int j=i+1; j<=n; ++j)
{
int q1, p1, flag=1;
q1=MRA[i];
p1=MRA[j];
for(int k=1; k<=m; k++)
if(a[i][q1+k-1]!=a[j][p1+k-1])
{
flag=0;
break;
}
if(flag)
sum++;
}
printf("%d", sum);
return 0;
}
C
数据水的一批,爆搜直接AC
#include<iostream>
#include<cstdio>
using namespace std;
int n, m, flag=0;
char a[2501][2501];
bool f[2501][2501], f1[2501][2501];
int dx[4]={0, 1, 0, -1};
int dy[4]={1, 0, -1, 0};
void dfs(int x1, int y1, int x, int y, int d)
{
if(flag)
return;
if(x1==x&&y1==y&&d>=4)
{
printf("Yes");
flag=1;
return;
}
for(int i=0; i<4; i++)
{
int xx=x+dx[i];
int yy=y+dy[i];
if(a[xx][yy]!=a[x][y]||xx<1||xx>n||yy<1||yy>m||f1[xx][yy]==1)
continue;
f1[xx][yy]=1;
dfs(x1, y1, xx, yy, d+1);
f1[xx][yy]=0;
}
}
int main()
{
cin>>n>>m;
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
scanf("%1s", &a[i][j]);
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
{
dfs(i, j, i, j, 0);
if(flag)
return 0;
}
printf("No");
return 0;
}
D
首先分别预处理奇数位偶数位的前缀和和后缀和。
如果去掉第i个数,那么前i个数不变,后面的数下标奇偶性取反
之后
O
(
n
)
O(n)
O(n)枚举位置并检查即可。
#include<iostream>
#include<cstdio>
using namespace std;
int n, a[1001000], b[1001000], a1, b1;
int t[1001000];
int main()
{
scanf("%d", &n);
for(int i=1; i<=n; i++)
{
scanf("%d", &t[i]);
if(i%2==0)
b[i]=b[i-1]+t[i],
a[i]=a[i-1];
else
b[i]=b[i-1],
a[i]=a[i-1]+t[i];
}
int sum=0;
for(int i=1; i<=n; i++)
{
int as, bs;
as=a[i-1]+b[n]-b[i],
bs=b[i-1]+a[n]-a[i];
if(as==bs)
sum++;
}
printf("%d", sum);
return 0;
}