實在沒忍住就去打比賽了而後一耗就是一天ios
最後Rank19仍是挺好的(要不是樂多賽否則炸飛),這是惟一一套在Luogu上號稱水題大賽的而實際上真的是水題大賽的比賽git
好了咱們開始看題數組
首先看到這道題你要先仔細想想切比雪夫距離是什麼less
咱們更加形象地理解一下就會知道這是一個等腰三角形(算了仍是看圖吧,對於紅色的格子,全部黃色的格子對於它都在北面):優化
而後仔細看一下就發現每個點能夠設計一個DP的思想(相似於過河卒):ui
CODEspa
#include<cstdio> #include<cctype> #include<cstring> using namespace std; const int N=1e3+5,fx[4]={0,1,0,-1},fy[4]={1,0,-1,0}; int n,m,k,h[N][N],x,y,f[N][N]; inline char tc(void) { static char fl[100000],*A=fl,*B=fl; return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++; } inline void read(int &x) { x=0; char ch; while (!isdigit(ch=tc())); while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc())); } inline void write(int x) { if (x>9) write(x/10); putchar(x%10+'0'); } inline bool check(int x,int y) { for (register int i=0;i<4;++i) { int xx=x+fx[i],yy=y+fy[i]; if (xx>=1&&xx<=n&&yy>=1&&yy<=m&&h[xx][yy]>=h[x][y]) return 0; } return 1; } inline int min(int a,int b) { return a<b?a:b; } int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); register int i,j; read(n); read(m); read(k); for (i=1;i<=n;++i) for (j=1;j<=m;++j) read(h[i][j]); memset(f,63,sizeof(f)); for (i=1;i<=n;++i) for (j=1;j<=m;++j) if (check(i,j)) f[i][j]=0; else f[i][j]=min(min(f[i-1][j-1],f[i-1][j]),f[i-1][j+1])+1; while (k--) { read(x); read(y); if (f[x][y]<n) write(f[x][y]),putchar('\n'); else puts("Pool Babingbaboom!"); } return 0; }
固然我比賽時不是這麼寫的設計
對於每一行處理出山的前綴和,而後查詢時暴力向上跳便可,指望複雜度爲\(O(klogn)\),最壞複雜度爲\(O(kn)\)code
CODEblog
// luogu-judger-enable-o2 #include<cstdio> #include<cctype> #include<cstring> using namespace std; const int N=1005,K=100005,fx[4]={0,1,0,-1},fy[4]={1,0,-1,0}; int h[N][N],l[N][N],n,m,k,INF,x,y; bool vis[N][N]; inline char tc(void) { static char fl[100000],*A=fl,*B=fl; return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++; } inline void read(int &x) { x=0; char ch; while (!isdigit(ch=tc())); while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc())); } inline void write(int x) { if (x>9) write(x/10); putchar(x%10+'0'); } inline bool check(int x,int y) { for (register int i=0;i<4;++i) { int xx=x+fx[i],yy=y+fy[i]; if (xx>=1&&xx<=n&&yy>=1&&yy<=m&&h[xx][yy]>h[x][y]) return 0; } return 1; } inline int max(int a,int b) { return a>b?a:b; } inline int min(int a,int b) { return a<b?a:b; } int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); register int i,j; read(n); read(m); read(k); for (i=1;i<=n;++i) for (j=1;j<=m;++j) read(h[i][j]); for (i=1;i<=n;++i) for (j=1;j<=m;++j) l[i][j]=l[i][j-1]+check(i,j); while (k--) { read(x); read(y); bool flag=0; for (i=x;i>=1;--i) if ((l[i][y]-l[i][max(y-x+i-1,0)])||(l[i][min(y+x-i,m)]-l[i][y-1])) { write(x-i); putchar('\n'); flag=1; break; } if (!flag) puts("Pool Babingbaboom!"); } return 0; }
這應該是一道狀壓板子題了(主要是作的時候狀態不是很好莫名很煩,而後都沒有想用String來存最優解,一算數組炸了就去寫暴力了)
咱們考慮狀壓,設\(f_{i,j}\)表示以第\(i\)(爲了方便以\([0,n)\)編號)個倉庫結尾且狀態爲\(j\)(爲二進制下的01串)的最優解
而後對於兩點間的距離咱們大力BFS預處理便可(存到\(dis_{i,j}\)中)
而後稍加推到便可得出狀態轉移方程:
\(f_{i,j\oplus(1<<i)}=f_{k,j}+dis_{k.i}\)
其中\(\oplus\)表示異或,感受這種轉移實在是太基礎了。
關於字典序的問題轉移的時候直接一塊兒搞便可(String在比較字典序是實在好用)
CODE
// luogu-judger-enable-o2 #include<cstdio> #include<iostream> #include<cctype> #include<algorithm> #include<cstring> #include<string> using namespace std; const int R=505,N=18,state=66000,fx[4]={0,1,-1,0},fy[4]={1,0,0,-1}; char a[R][R],ch; int r,c,x[N],y[N],n,dis[R][R],q[R*R][2],step[R][R],tot,f[N][state],num,INF,MIN; bool vis[R][R]; string g[N][state]; inline void BFS(int id,int x,int y) { register int i,H=0,T=1; q[1][0]=x; q[1][1]=y; step[x][y]=0; vis[x][y]=1; while (H<T) { int xx=q[++H][0],yy=q[H][1]; if (isalpha(a[xx][yy])) dis[id][a[xx][yy]-'A']=step[xx][yy]; for (i=0;i<4;++i) { int xxx=xx+fx[i],yyy=yy+fy[i]; if (xxx>0&&xxx<=r&&yyy>0&&yyy<=c&&a[xxx][yyy]!='*'&&!vis[xxx][yyy]) step[xxx][yyy]=step[xx][yy]+1,q[++T][0]=xxx,q[T][1]=yyy,vis[xxx][yyy]=1; } } } int main() { register int i,j,k; cin>>r>>c>>n; for (i=1;i<=r;++i) for (j=1;j<=c;++j) { cin>>a[i][j]; if (isalpha(a[i][j])) x[a[i][j]-'A']=i,y[a[i][j]-'A']=j; } memset(dis,63,sizeof(dis)); memset(f,63,sizeof(f)); for (i=0;i<n;++i) memset(vis,0,sizeof(vis)),BFS(i,x[i],y[i]); tot=(1<<n)-1; f[0][1]=0; INF=f[0][0]; g[0][1]="A"; for (j=1;j<=tot;++j) for (i=1;i<n;++i) { if (j&(1<<i)) continue; for (k=0;k<n;++k) if (k^i&&(j&(1<<k))) { if (f[k][j]==INF) continue; if (f[i][j^(1<<i)]>f[k][j]+dis[k][i]) f[i][j^(1<<i)]=f[k][j]+dis[k][i],ch=i+'A',g[i][j^(1<<i)]=g[k][j],g[i][j^(1<<i)]+=ch; if (f[i][j^(1<<i)]==f[k][j]+dis[k][i]&&g[i][j^(1<<i)]>g[k][j]) ch=i+'A',g[i][j^(1<<i)]=g[k][j],g[i][j^(1<<i)]+=ch; } } for (MIN=INF,i=1;i<n;++i) { if (f[i][tot]<MIN) MIN=f[i][tot],num=i; if (f[i][tot]==MIN&&g[i][tot]<g[num][tot]) num=i; } printf("%d\n",MIN); cout<<g[num][tot]; return 0; }
一道很神奇的數學題,%%%yekehe大佬5min切掉此題。
咱們首先發現罰時的位置和最後一次AC都是要計算上去的,所以咱們先加上去便可。
而後對答案有影響的只有那B條綠鯉魚
而後咱們固定第一個AC的位置,而後後面只有\(A+B-1\)個位置要填上\(B-1\)個AC
那還等什麼,組合數大法好,接下來由於每一位對答案的貢獻都是同樣的,所以咱們直接乘上去便可。
而後別忘了這是指望,還有除以總方案數\(C_{A+B}^B\)
而後我就開始暴力計算了,對於多個階乘和逆元都一塊兒作。
而後正常人這麼寫都GG了(常數太大)
而後我就第一個不服了,以後開始了我一下午的卡常工做(都ZZ地沒有再接下去想一步)
最後卡時間A了!(而後就被尊稱爲常數之王了)
一下總結幾點卡常技巧:
卡常CODE
// luogu-judger-enable-o2 #pragma G++ optimize (2) #include<cstdio> using namespace std; typedef unsigned long long ull; const ull mod=998244853,less=998244851; ull n,m; inline ull quick_pow(ull x,ull p) { ull tot=1; while (p) { if (p&1) tot=1LL*tot*x%mod; x=1LL*x*x%mod; p>>=1; if (p&1) tot=1LL*tot*x%mod; x=1LL*x*x%mod; p>>=1; if (p&1) tot=1LL*tot*x%mod; x=1LL*x*x%mod; p>>=1; } return tot; } int main() { register ull i; scanf("%lld %lld",&n,&m); n%=mod; static ull ans=1,t=1; for (i=1;i+9<m;i+=10) { t=t*quick_pow(i,less)%mod; t=t*quick_pow(i+1,less)%mod; t=t*quick_pow(i+2,less)%mod; t=t*quick_pow(i+3,less)%mod; t=t*quick_pow(i+4,less)%mod; t=t*quick_pow(i+5,less)%mod; t=t*quick_pow(i+6,less)%mod; t=t*quick_pow(i+7,less)%mod; t=t*quick_pow(i+8,less)%mod; t=t*quick_pow(i+9,less)%mod; } for (;i<m;++i) t=t*quick_pow(i,less)%mod; for (i=n+1;i+9<n+m;i+=10) { t=t*i%mod; t=t*(i+1)%mod; t=t*(i+2)%mod; t=t*(i+3)%mod; t=t*(i+4)%mod; t=t*(i+5)%mod; t=t*(i+6)%mod; t=t*(i+7)%mod; t=t*(i+8)%mod; t=t*(i+9)%mod; } for (;i<n+m;++i) t=t*i%mod; ans=5*t%mod; ans=ans*(n+m+1)%mod*(n+m)%mod*quick_pow(2,less)%mod; ans=ans*quick_pow(t*quick_pow(m,less)%mod*(n+m)%mod,less)%mod; return printf("%lld",((10*n+5*m+5)%mod+ans)%mod),0; }
而後若是你多想1min就能夠發現上面的式子:
\(\frac{5(2A+B+1)+5\cdot C_{B+A−1}^{B-1}\cdot (A+B+1)\cdot \frac{(A+B)}{2}}{2}\)=\(5\cdot(2A+B+1)+5B\cdot(A+B+1)\)
而後直接\(O(1)\)求便可
CODE
#pragma G++ optimize (2) #include<cstdio> using namespace std; typedef unsigned long long ull; const ull mod=998244853; ull n,m; inline ull quick_pow(ull x,ull p) { ull tot=1; while (p) { if (p&1) tot=1LL*tot*x%mod; x=1LL*x*x%mod; p>>=1; } return tot; } int main() { register ull i; scanf("%lld %lld",&n,&m); n%=mod; static ull ans=1; ans=ans*(n+m+1)%mod*(n+m)%mod*quick_pow(2,mod-2)%mod; ans=5*ans*quick_pow(n+m,mod-2)%mod*m%mod; return printf("%lld",((10*n+5*m+5)%mod+ans)%mod),0; }