2019河北省赛补题感悟
对于B题
链接:https://ac.nowcoder.com/acm/contest/903/B
来源:牛客网
看似是一个求一个等比数列的前n项和,似乎利用高中学的知识,a1(1-qn)/1-q在对p取模,可以利用同余定理,求分子的取余在乘以分母的取余,对于分母取余,可以用到乘法逆元,a*
ap-2=1(modp),用该定理需要考虑到gcd(a,p)=1,因为题目中并没有显示的给出两个数互质,所以该方法不行。
接下来就想着用矩阵快速幂来解决它。
先找出对应关系
Sn=qSn-1+q
q=0*Sn-1+q
所以矩阵可表示为
Sn=(q q) (Sn-1)
q =(0 q) ( q )
进而
Sn=(q q) n-1 (S1)
q =(0 q) ( q ) 然而S1=q
所以就可求解出答案,接下来看代码
#include<iostream> #include<cstring> using namespace std; typedef long long ll; ll p; struct Matrix{ ll a[10][10]; int x,y; Matrix operator* (Matrix b) { Matrix ans; memset(ans.a,0,sizeof(ans.a)); ans.x=x; ans.y=b.y; for(int i=0;i<=ans.x;i++) for(int j=0;j<=ans.y;j++) for(int k=0;k<=y;k++) ans.a[i][j]=(ans.a[i][j]+a[i][k]*b.a[k][j])%p; return ans; } }; Matrix mpow(Matrix a,ll b) { Matrix ans; memset(ans.a,0,sizeof(ans.a)); for(int i=0;i<=a.x;i++) ans.a[i][i]=1; ans.x=a.x; ans.y=a.y; while (b) { if (b&1) ans=ans*a; a=a*a; b>>=1; } return ans; } int main() { int q,t,n; Matrix o; o.x=1; o.y=1; Matrix one; one.x=1; one.y=0; cin>>t; while(t--) { cin>>q>>n>>p; o.a[0][0]=q; o.a[0][1]=1; o.a[1][0]=0; o.a[1][1]=1; one.a[0][0]=q; one.a[1][0]=q; Matrix s=mpow(o,n-1)*one; cout<<s.a[0][0]<<endl; } return 0; }
对于H题:天神的密码
链接:https://ac.nowcoder.com/acm/contest/903/H
来源:牛客网
本来并没有多大难度,但是如果他的K值不在是0-2,而是非常大,又该如何求解呢?
此时我们学要运用到一个求余的法则:
X=Nk
X%9==(X的每一位相加)%9
why?
X%9==(a1*10n-1+a2*10n-2+.......an)%9==(a1*10n-1)%9+(a2*10n-2)%9+.....an%9==(a1%9)*(10n-1)%9.......=(a1+a2+a3+.....an)%9
而X我们可以用快速幂取模算出结果,由结果来反推各项相加的和(和小于10)
因此求余结果为0,则何为9,否则求余多少结果便是多少。
#include<iostream> using namespace std; typedef long long ll; ll n,k;//当k无限次大时 ll qmpow(ll nn,ll x) { ll ans=1; while(x) { if(x&1) ans=(ans*nn)%9; nn=(nn*nn)%9; x>>=1; } return ans; } int main() { ll t,i,j; cin>>t; while(t--) { cin>>n>>k; if(qmpow(n,k)==0) cout<<"9"<<endl; else cout<<qmpow(n,k)<<endl; } return 0; }
L Smart Robot
链接:https://ac.nowcoder.com/acm/contest/903/L
来源:牛客网
这道题是一道典型的搜索题,难点在于求它最多应该搜多少步结束,先说一下思路,通过一个数组记录它达到该数下标时,令他下标的数字为1,最后通过循环判断不是1的那个数的下标就是最终答案。
博主比较菜,算不出来,随意代了一个5,就过了。
#include<iostream> #include<cstring> using namespace std; int n,a[55][55]; int b[9000000]; int v[55][55]; int x[4]={0,0,1,-1},y[4]={1,-1,0,0}; void dfs(int c,int d,int step,int val) { int xx,yy,i; // v[c][d]=1; if(step>=5) return ; for(i=0;i<4;i++) { xx=c+x[i]; yy=d+y[i]; if(xx>=1&&xx<=n&&yy>=1&&yy<=n&&v[xx][yy]==0) { int p=val*10+a[xx][yy]; b[p]=1; dfs(xx,yy,step+1,p); } } return ; } int main() { int i,j,k; cin>>n; for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { cin>>a[i][j]; b[a[i][j]]=1; } } for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { memset(v,0,sizeof(v)); dfs(i,j,1,a[i][j]); } } for(i=0;;i++) { if(b[i]==0) { cout<<i<<endl; break; } } return 0; }
C 分治
链接:https://ac.nowcoder.com/acm/contest/903/C
来源:牛客网
该题最重要的就是推出: dp[l][r]=min(dp[l][r],cost[i]*(r-l)+dfs(i+1,r)+dfs(l,i-1));
再利用记忆化数组,优化速度。
#include<iostream> #include<cstring> #include<cmath> using namespace std; #define inf 0x3f3f3f3f int dp[101][101]; int cost[101]; int t,n; int dfs(int l,int r) { if(l>=r) return 0; if(dp[l][r]!=inf) return dp[l][r]; for(int i=l;i<=r;i++) dp[l][r]=min(dp[l][r],cost[i]*(r-l)+dfs(i+1,r)+dfs(l,i-1)); return dp[l][r]; } int main() { int i,j,k,ans; cin>>t; while(t--) { cin>>n; memset(dp,0x3f,sizeof(dp)); for(i=1;i<=n;i++) cin>>cost[i]; ans=dfs(1,n); cout<<ans<<endl; } return 0; }