2021牛客OI赛前集训营-方格计数【计数,dp】
正題
題目鏈接:https://ac.nowcoder.com/acm/contest/20107/B
題目大意
給出一個w×hw\times hw×h的網(wǎng)格圖,然后要求在上面選出nnn個格點,使得它們在一條直線上且兩兩之間距離不小于ddd。
1≤T≤20,1≤w,h,d≤500,1≤n≤501\leq T\leq 20,1\leq w,h,d\leq 500,1\leq n\leq 501≤T≤20,1≤w,h,d≤500,1≤n≤50
解題思路
先只考慮橫豎和斜向右下的直線
顯然是枚舉直線更加迅速,可以枚舉一個斜率ab\frac{a}{b}ba?,然后為了防止算重我們考慮起點也就是我們選擇的最第一個點,對于起點在(0,0)~(w?ka,h?kb)(0,0)\sim (w-ka,h-kb)(0,0)~(w?ka,h?kb)的矩形內(nèi)的點,右下角至少還有kkk個點可以選擇,我們可以枚舉這個kkk,然后暴力統(tǒng)計。這樣一次復(fù)雜度是O(min{wa,hb})O(min\{\frac{w}{a},\frac{h}{b}\})O(min{aw?,bh?}),類似于調(diào)和級數(shù)不是很大。
之后考慮統(tǒng)計選擇的方案,設(shè)fi,j,kf_{i,j,k}fi,j,k?表示選擇的兩個之間要至少相隔iii,有jjj個可以選,選擇kkk個的方案,這個可以直接dpdpdp。
就可以過了,時間復(fù)雜度:O(whn+Twhlog?wh)O(whn+Twh\log {wh})O(whn+Twhlogwh)
code
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define ll long long using namespace std; const ll N=510,P=1e9+7; ll T,n,w,h,D,ans,d[N][N]; int f[N][N][N]; signed main() {scanf("%lld",&T);for(ll i=1;i<=500;i++)d[i][0]=d[0][i]=i;for(ll i=1;i<=500;i++)for(ll j=1;j<=i;j++)d[i][j]=d[j][i]=d[j][i%j];for(ll i=1;i<=500;i++){f[i][0][0]=1;for(ll j=1;j<=500;j++){for(ll k=0;k<=500;k++)f[i][j][k]=f[i][j-1][k];if(j>=i)for(ll k=1;k<=500;k++)(f[i][j][k]+=f[i][j-i][k-1])%=P;}}while(T--){scanf("%lld%lld%lld%lld",&n,&w,&h,&D);if(n==1){printf("%lld\n",(w+1)*(h+1)%P);continue;}ans=0;for(ll i=0;i<=w;i++)for(ll j=0;j<=h;j++){if(d[i][j]!=1)continue;ll k,last=0,ub=1;if(i!=0&&j!=0)ub=2;ll dis=ceil(D/sqrt(i*i+j*j));for(k=1;k;k++){if(k*i>w||k*j>h)break;ll L=w-k*i+1;ll R=h-k*j+1;(ans+=L*R%P*(1ll*(f[dis][k][n-1]-f[dis][k-1][n-1]))*ub%P)%=P;}}printf("%lld\n",(ans+P)%P);}return 0; }總結(jié)
以上是生活随笔為你收集整理的2021牛客OI赛前集训营-方格计数【计数,dp】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2021牛客OI赛前集训营-树数树【树上
- 下一篇: 中国5个直辖市是那几个 中国直辖市简述