2020.10.26 【NOIP2014】普及组模拟赛总结
程序员文章站
2022-05-12 12:29:19
...
题号 | 题目 |
---|---|
T1 | 魔法部落 |
T2 | 圆盘 |
T3 | 棋盘行走 |
T4 | 走方格 |
得分 | 255/400 |
T1
思路
本题使用等比数列求和公式即可得到以下答案:
a
n
s
=
(
3
n
−
1
)
2
ans=\frac{ (3^n−1)}{2}
ans=2(3n−1)
发现➗不能直接取模,所以求逆元。
加上快速幂便可在log的复杂度内解决本题。
代码
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const int MOD=1000000007;
long long n,ans=1,js;
long long poww(long long x,long long y)
{
long long ans=1;
while(y!=0)
{
if(y&1)
ans=(ans*x)%MOD;
x=(x*x)%MOD;
y>>=1;
}
return ans%MOD;
}
int main()
{
cin>>n;
js=(3*(1-poww(3,n))%MOD)*(MOD+1)/-2%MOD+1;
cout<<js;
return 0;
}
T2
思路
这里用最小表示法来做。可以在
O
(
n
2
)
O(n^2)
O(n2) 求出所有对最小表示,
然后
O
(
n
)
O(n)
O(n) 统计有多少对相同的最小表示,即可AC。
对于最小表示法,我这里先不做详细解释,
以后我会专门写一篇博客来讲这个算法,并附上链接。
代码
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int a[10101],b[1010][1010];
int n,m,p,w,ans,fl,ZXBS[1010];
int zxbs(int t[],int n)
{
int x=1,y=2,k=0;
while(x<=n&&y<=n)
{
k=0;
while(t[x+k]==t[y+k]&&k<=n)
k++;
if(k==n)
break;
if(t[x+k]<t[y+k])
{
x=x+k+1;
if(x==y)
x++;
}
else
{
y=y+k+1;
if(x==y)
y++;
}
}
return min(x,y);
}
int main()
{
cin>>n>>m>>p;
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++)
scanf("%d",&a[j]);
sort(a+1,a+1+m);
for(int j=1; j<=m-1; j++)
b[i][j]=abs(a[j+1]-a[j]),b[i][m+j]=b[i][j];
b[i][m]=b[i][2*m]=a[1]+p-a[m];
ZXBS[i]=zxbs(b[i],2*m); //预处理最小表示可将时间复杂度优化成O(nm+logn+n^2)
}
for(int i=1; i<=n; i++)
for(int j=i+1; j<=n; j++)
{
fl=1;
int p=ZXBS[i];
int q=ZXBS[j];
for(int k=1; k<=m; k++)
if(b[i][p+k-1]!=b[j][q+k-1])
{
fl=0;
break;
}
if(fl)
ans++;
}
cout<<ans;
return 0;
}
T3
思路
数据水的一批,爆搜可直接AC。
代码
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const int dx[5]={0,0,1,0,-1};
const int dy[5]={0,1,0,-1,0};
int v[2510][2510];
char a[2510][2510];
int n,m,s,t,w;
inline void dfs(int x,int y,int dep)
{
if(w==1)
return;
if(dep>=4&&x==s&&y==t)
{
w=1;
return;
}
for(register int i=1; i<=4; i++)
{
int xx=x+dx[i];
int yy=y+dy[i];
if(!(xx>=1&&xx<=n&&yy>=1&&yy<=m&&v[xx][yy]==0&&a[x][y]==a[xx][yy]))
continue;
v[xx][yy]=1;
dfs(xx,yy,dep+1);
v[xx][yy]=0;
}
}
int main()
{
cin>>n>>m;
for(register int i=1; i<=n; i++)
for(register int j=1; j<=m; j++)
scanf("%1s",&a[i][j]);
for(register int i=1; i<=n; i++)
for(register int j=1; j<=m; j++)
{
s=i,t=j;
dfs(i,j,0);
if(w==1)
{
cout<<"Yes";
return 0;
}
}
cout<<"No";
return 0;
}
T4
思路
首先分别预处理奇数位偶数位的前缀和。
如果去掉第
i
i
i 个数,那么前 $i4 个数不变,后面的数下标奇偶性取反
之后
O
(
n
)
O(n)
O(n) 枚举位置并检查即可。
代码
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int a[200010],b[200010],c[200010];
int n,js1,js2,ans,w;
int main()
{
cin>>n;
for(int i=1; i<=n; i++)
scanf("%d",&a[i]);
for(int i=1; i<=n; i++)
if(i%2==0)
b[i]=b[i-1]+a[i],c[i]=c[i-1];
else
c[i]=c[i-1]+a[i],b[i]=b[i-1];
for(int i=1; i<=n; i++)
{
int b_sum=b[i-1]+c[n]-c[i];
int c_sum=c[i-1]+b[n]-b[i];
if(c_sum==b_sum)
ans++;
}
cout<<ans;
return 0;
}
上一篇: js中的栈、堆、队列、内存空间