2019.8.19小结
T1 阶乘 100/100
题意
T组数据,给出N,求出N!最右边非零的数。
对于30%的数据,N <= 30,T<=10。
对于全部的数据,N <= 10^2009,T<=30。
一道数学题
解析
N!/(10x)最后一位数字即是结果。10x进行拆分,变成5x*2x。怎么除以5^x呢,好办,乘的时候含有5的倍数的一项全部不乘进去,再递归此过程。即
1 2 3 4 (15) 6 7 8 9 (25)
11 12 13 14 (35)16 17 18 19 (45)
21 22 23 24 (55) 26 27 28 29 (65) ...
再递归处理
1 2 3 4 (1*5) 6
而且可以发现,不算5倍数一项进去,每十个一组,最末尾结果是一样的:6,且6*6还是6!
接下来的问题,怎么除2^x呢?
分析发现:
2^0 = 1
2^1 = 2
2^2 = 4
2^3 = 8
2^4 =16=(6)
且2,4,6,8乘以6最末尾还是原来的数。所以,可以分析看x%4是多少,若为1,说明原来的结果相当于多乘了一个2(其他的那些2刚好是4的倍数,不影响结果),所以,我们本来是要除以2的,但是很显然对结果再补乘3个2(2^3)即可消除影响,得到正确答案。其他情况同理。至此,思路理顺。
代码
#include<bits/stdc++.h>
using namespace std;
int T,n,ans,mod,rest,x;
bool flag;
const int v[10]={1,1,2,6,4,4,4,8,4,6};
char s[3000];
int a[3000];
const int k[4]={6,8,4,2};
int main(){
scanf("%d",&T);
while(T--){
scanf("%s",s);
memset(a,0,sizeof(a));
n=strlen(s);
for(int i=1;i<=n;++i){
a[i]=s[n-i]-'0';
}
ans=1;
mod=0;
flag=0;
while(1){
rest=0;
ans=(ans*v[a[1]])%10;
if(n>1) ans=(ans*6)%10;
for(int i=n;i>=1;i--){
x=rest*10+a[i];
rest=x%5;a[i]=x/5;
}
while((n>0)&&(a[n]==0)) n--;
if(n==0) break;
flag=true;
mod=(mod+a[2]*10+a[1])%4;
}
if(flag) ans=(ans*k[mod])%10;
printf("%d\n",ans);
}
return 0;
}
T2 拐弯 30/90
题意
给出n* n 的图,A为起点,B为终点,*为障碍,.可以行走,问最少需要拐90度的弯多少次,无法到达输出-1。
解析
考场爆搜以为大部分过不去,结果有90分
思路:构造N * M * 4个点,即将原图的每个点分裂成4个点。其中点(i,j,k)表示在(i,j)时人的方向是k,然后对于两个点(i,j,k)和(i,j,kk),如果k和kk是两个旋转90度能转换的方向,就连一条边权为1的边,而对于(i,j,k)和(i+dx[ k],j+dy[k],k)连一条边权为0的边,表示从(i,j)在方向为k的情况下能向k方向走一步到达(i+dx[k],j+dy[k],k)。因为起始和终止的方向不确定,故再添加一个源点和一个汇点,源点向起始位置四个方向连边权为0的边,汇点向终止位置四个方向连边权为0的边,然后求源点到汇点的最短路即可。
爆搜代码
#include<bits/stdc++.h>
using namespace std;
int n,sx,sy,ex,ey,a[110][110];
char k;
bool book[110][110];
int ans=1<<30;
bool cheak(int x,int y){
if(x<1||y>n||y<1||x>n||a[x][y]||book[x][y]) return false;
else return true;
}
void dfs(int x,int y,int dir,int step){
if(x==ex&&y==ey){
ans=min(step,ans);
return;
}
if(step>ans) return;
if(dir){
if(cheak(x+1,y)){
book[x+1][y]=1;
dfs(x+1,y,dir,step);
book[x+1][y]=0;
}
if(cheak(x-1,y)){
book[x-1][y]=1;
dfs(x-1,y,dir,step);
book[x-1][y]=0;
}
if(cheak(x,y+1)){
book[x][y+1]=1;
dfs(x,y+1,0,step+1);
book[x][y+1]=0;
}
if(cheak(x,y-1)){
book[x][y-1]=1;
dfs(x,y-1,0,step+1);
book[x][y-1]=0;
}
}
else{
if(cheak(x+1,y)){
book[x+1][y]=1;
dfs(x+1,y,1,step+1);
book[x+1][y]=0;
}
if(cheak(x-1,y)){
book[x-1][y]=1;
dfs(x-1,y,1,step+1);
book[x-1][y]=0;
}
if(cheak(x,y+1)){
book[x][y+1]=1;
dfs(x,y+1,dir,step);
book[x][y+1]=0;
}
if(cheak(x,y-1)){
book[x][y-1]=1;
dfs(x,y-1,0,step);
book[x][y-1]=0;
}
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
scanf("%c",&k);
if(k=='A'){
sx=i;
sy=j;
}
else if(k=='B'){
ex=i;
ey=j;
}
else if(k=='x'){
a[i][j]=1;
}
else if(k=='.'){
a[i][j]=0;
}
else j--;
}
}
dfs(sx,sy,0,0);
dfs(sx,sy,1,0);
if(ans==1<<30) printf("-1");
else printf("%d",ans);
return 0;
}
T3 天天爱跑步 20/20
题意
自行百度 noip题
考场按特殊点打的,20分。
代码
T4 填数游戏 100/95
题意
自行百度 noip题
解析:规律题,证明等以后来补
考场快速幂取模有点问题,溢出了,所以丢了5分
代码
#include<bits/stdc++.h>
using namespace std;
long long n,m;
long long ans;
long long f[10];
const long long mod=1e9+7;
long long power(int x,int y){
long long tmp=1;
while(y){
if(y&1) tmp=(x*tmp)%mod;
x=(x%mod*x%mod)%mod;
y>>=1;
}
return tmp;
}
int main(){
scanf("%lld %lld",&n,&m);
f[1]=2;
for(int i=2;i<=9;++i){
f[i]=f[i-1]*2;
}
if(n>m) swap(n,m);
if(n==1){
ans=power(2,m);
printf("%lld",ans%mod);
return 0;
}
else if(n==2) ans=12;
else if(n==3) ans=112;
else if(n==4) ans=912;
else{
ans=912;
for(int i=5;i<=n;++i){
ans=(ans*8-5*f[i])%mod;
}
}
if(m==n+1&&n>3) ans=ans*3-3*f[n];
else if(m==n+1) ans=ans*3;
if(m>n+1){
if(n>3) ans=ans*3-3*f[n];
else ans=ans*3;
for(int i=n+2;i<=m;++i){
ans=ans*3%mod;
}
}
printf("%lld",ans%mod);
return 0;
}