BZOJ 1867 [Noi1999]钉子和小球 DP
想状态和钉子的位置如何匹配想了半天。。。后来发现不是一样的吗$qwq$
思路:当然是$DP$啦
提交:>5次(以为无故$RE$,实则是先乘后除爆了$long\space long$)
题解:
若有钉子,左右各乘$\frac{1}{2}$转移,否则,向下两层直接转移。
对于分数,分别维护分子和分母,然后加起来的时候,记着一定要写成
up[i][j]=up[i][j]*(b/G)+a*(dn[i][j]/G);
dn[i][j]=dn[i][j]*(b/G);
而非
up[i][j]=up[i][j]*b/G+a*dn[i][j]/G;
dn[i][j]=dn[i][j]*b/G;
(好吧也是我傻$qwq$)
代码:
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; #define ull unsigned long long #define ll long long #define R register ll #define pause (for(R i=1;i<=10000000000;++i)) #define In freopen("NOIPAK++.in","r",stdin) #define Out freopen("out.out","w",stdout) namespace Fread { inline int g() { R ret=0,fix=1; register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-1:fix; if(ch==EOF) return EOF; do ret=ret*10+(ch^48); while(isdigit(ch=getchar())); return ret*fix; } inline bool isempty(const char& ch) {return (ch<=36||ch>=127);} inline void gs(char* s) { register char ch; while(isempty(ch=getchar())); do *s++=ch; while(!isempty(ch=getchar())); } } using Fread::g; using Fread::gs; namespace Luitaryi { const int N=60; int n,m; ll up[N][N],dn[N][N]; bool w[N][N]; inline ll gcd(ll a,ll b){ return b?gcd(b,a%b):a; } inline void add(int i,int j,ll a,ll b) { R G=gcd(dn[i][j],b); up[i][j]=up[i][j]*(b/G)+a*(dn[i][j]/G); dn[i][j]=dn[i][j]*(b/G); G=gcd(up[i][j],dn[i][j]); if(G) up[i][j]/=G,dn[i][j]/=G; } inline void main() { n=g(),m=g()+1; for(R i=1;i<=n;++i) for(R j=1;j<=i;++j) { register char ch; while(ch=getchar(),ch!='*'&&ch!='.'); w[i][j]=(ch=='*'); up[i][j]=0,dn[i][j]=1; } for(R i=1;i<=n;++i) up[n+1][i]=0,dn[n+1][i]=1; up[1][1]=dn[1][1]=1; for(R i=1;i<=n;++i) for(R j=1;j<=i;++j) { R a=up[i][j],b=dn[i][j]; if(w[i][j]) { if(a%2==0) a/=2; else b*=2; add(i+1,j,a,b),add(i+1,j+1,a,b); } else add(i+2,j+1,a,b); } printf("%lld/%lld",up[n+1][m],dn[n+1][m]); } } signed main() { Luitaryi::main(); }
2019.07.17