2021CCPC華為雲挑戰賽 部分題題解


CDN流量調度問題

題看了沒多久就看出來是\(DP\)的題,然后就設了狀態\(f[i][j]\)表示到前\(i\)個點時已經用了\(j\)個節點的最小總代價,結果發現轉移時\(O(nm^2)\),但這樣只會T掉的,於是就順利應當的進入了DP優化的思維,奈何無論用上什么伎倆都好像有點不太奏效,以下給出暴力的代碼:

rep(i,1,n)    rep(j,0,m)
            rep(k,1,min(j+1,t[i]))//枚舉i的節點數量。
                f[i][j]=min(f[i][j],f[i-1][j+1-k]+a[i]/k+(a[i]%k?1:0));

發現難點就在於轉移時,\(a[i]/k\)(向上取整)這個沒法很好的處理....之后看來看題解,發現果然是在這里做文章的,這里考慮我們暴力的做法k的范圍從1到min(j+1,t[i]),相當於將所有可能的都枚舉了。但再仔細的瞅一眼上面這個式子,\(a[i]/k=t\)(這里向上取整)。也就是說\(a[i]=k*t\)\(k\)\(t\)不就是\(a[i]\)的因子嗎?不不不...這里由於是向上取整的緣故,所以不是嚴格意義下的因子,因為我們可以發現對於任意一個數,它都能除以其他數在向下取整的情況下。那我們怎么辦呢?考慮到是向上取整的緣故,所以一定有\(k*t>=a[i]\),並且要求\(k\)\(a[i]\)一定時,\(t\)最小,這樣的話,我們也可以通過枚舉所謂“因子”的方法枚舉\(k\),若因為k和t是成對存在的我們枚舉小的那個,這樣的話,我們枚舉的范圍就是\(\sqrt{a[i]}\)
怎么說呢,這個題反正到最后還是有點不很理解的...
為什么這個k得枚舉范圍就降了一個\(\sqrt{a[i]}\),大概可以這么說吧,就是你通過分析這個\(a[i]/k\)向上取整這個得值最多是2*\(\sqrt{a[i]}\),所以有很多的k,\(a[i]/k\)向上取整對應的值都一樣的,這樣的情況下,你就根本沒必要去枚舉那些多余的k值,你只需要知道\(a[i]/k\)有多少個值,並且他們所對應的最小的k就行了,大的k但和他們貢獻相同的就不用枚舉了....通過預處理,可以提前縮短我們遍歷的狀態空間,可以說這個題給我帶來的啟示很大!

//不等,不問,不猶豫,不回頭.
#include<bits/stdc++.h>
#define _ 0
#define ls p<<1
#define db double
#define rs p<<1|1
#define P 1000000007
#define RE register
#define ll long long
#define INF 1000000000
#define get(x) x=read()
#define PLI pair<ll,int>
#define PII pair<int,int>
#define ull unsigned long long
#define put(x) printf("%d\n",x)
#define putl(x) printf("%lld\n",x)
#define rep(x,y,z) for(int x=y;x<=z;++x)
#define fep(x,y,z) for(int x=y;x>=z;--x)
#define go(x) for(RE int i=link[x],y=a[i].y;i;y=a[i=a[i].next].y)
using namespace std;
const int N=105,M=10050;
int T,n,m,a[N],t[N],f[N][M],size[N];//f[i][j]表示前i個線路用了j的節點的最小代價。
PII v[N][M];//預處理出每個線路的所有不同的向上取整的結果已及所需的節點數。 

inline int read()
{
    int x=0,ff=1;
    char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
    while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*ff;
}

int main()
{
	//freopen("1.in","r",stdin);
    get(T);
    while(T--)
    {
        get(n);get(m);
        rep(i,1,n) get(a[i]);
        rep(i,1,n) get(t[i]);
        memset(f,0x3f,sizeof(f));
        memset(size,0,sizeof(size));
        f[0][0]=0;
        rep(i,1,n) 
		{
			int temp=0;
				rep(j,1,t[i])
			{
				if(a[i]/j+(a[i]%j?1:0)!=temp)
				{
					temp=a[i]/j+(a[i]%j?1:0);
					v[i][++size[i]]={temp,j};
				}
			}
		} 
        rep(i,1,n) rep(j,0,m)
		{
			if(j) f[i][j]=min(f[i][j],f[i][j-1]);
			rep(l,1,size[i])
			{
				if(v[i][l].second-1>j) break;
				f[i][j]=min(f[i][j],f[i-1][j+1-v[i][l].second]+v[i][l].first);
			}
		}
        put(f[n][m]);
    }
    return (0^_^0);
}
//以吾之血,鑄吾最后的亡魂.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM