牛客小白月赛92--CDE题解

C-耕种时间到

思路:模拟即可o(log3(1e9)*log3(1e9)*n)

int arr[100005];
void solve(){
    int n; cin>>n;
    int ans=0,cur=0;
    for(int i=1;i<=n;i++) cin>>arr[i];
    int k; cin>>k;
    for(int f=0;f<=19;f++){
        int cur=0;
        for(int i=1;i<=n;i++){
            int times=f,have=1,num=arr[i];
            while(times--){
                num=ceil((1.0*num)/3.0);
                have*=2;
            }
            if(num==k) cur+=have;
        }
        ans=max(ans,cur);
    }
    cout<<ans;
}

D-探索的时光

思路:公式化简。

f(i)=(x-i)*(x-i)*ai

若n=3:danger=(a1+a2+a3)*x^2-(2a1+4a2+6a3)*x+1a1+4a2+9a3;  这是一个开口向上的一元二次方程,最低点x=-b/(2*a)

void solve(){           //D  公式!化简!
    //f(i)=(x-i)*(x-i)*ai
    //若n=3:danger=(a1+a2+a3)*x^2-(2a1+4a2+6a3)*x+1a1+4a2+9a3;  这是一个开口向上的一元二次方程,最低点x=-b/(2*a)
    int suma=0,sumb=0,sumc=0;
    int n; cin>>n;
    for(int i=1;i<=n;i++){
        int x; cin>>x;
        suma+=x,sumb-=2*i*x,sumc+=i*i*x;            //sumb是负的
    }
    int lowest1=(-sumb)/(2*suma);           //因为只能取整数,lowest1不一定是最低的,可能往左偏或往右偏。
    int lowest2=lowest1+1;
    int lowest3=lowest1-1;
    int ans1=suma*lowest1*lowest1+sumb*lowest1+sumc;    //这里是+sumb
    int ans2=suma*lowest2*lowest2+sumb*lowest2+sumc;
    int ans3=suma*lowest3*lowest3+sumb*lowest3+sumc;
    cout<<min({ans1,ans2,ans3});
}

E-来硬的

思路:01背包.要注意的是x太大了,到达了1e9.数组开不到这么大,也不能枚举到这么大。但是题目保证n*m<=1e6.且sumx>=m。所以如果x>=m,当前获得铁矿石状态直接从已有0铁矿石状态转移即可。

////无空间优化
int n,m;
void solve(){           //E--01背包
	cin>>n>>m;
	////dp[i][j][0]  定义为:考虑前i个物品,获得j铁矿石,从来没使用魔法,最短耗时为dp[i][j][0].
	vector<vector<vector<int>>> dp(n+10,vector<vector<int>>(m+10,vector<int>(2,INT_MAX)));////0x3f3f3f3f不够大。。
	pair<int,int> arr[n+10];
	for(int i=1;i<=n;i++) cin>>arr[i].first>>arr[i].second;   //first为铁矿石,second为耗时
	dp[0][0][0]=0,dp[0][0][1]=0;  ////init
	for(int i=1;i<=n;i++){
		int w=arr[i].first,t=arr[i].second;
		for(int j=0;j<=m;j++){
			//不使用魔法的转移
			dp[i][j][0]=min(dp[i-1][j][0],dp[i-1][max(j-w,0ll)][0]+t);  //dp=min(不拿,拿)--ps:如果w>=j,那么直接从状态0转移!!
			dp[i][j][1]=min(dp[i-1][j][1],dp[i-1][max(j-w,0ll)][1]+t);
			//使用魔法
			dp[i][j][1]=min(dp[i][j][1],dp[i-1][max(j-2*w,0ll)][0]+t/2);
		}
	}
	cout<<dp[n][m][1];
}
//空间优化的
int n,m;
void solve(){
	cin>>n>>m;
    ////dp[j][0] 定义为从未使用魔法,得到j铁矿石需要的最少时间为dp[j][0]
	vector<vector<int>> dp(m+10,vector<int>(2,INT_MAX));
	pair<int,int> arr[n+10];
	for(int i=1;i<=n;i++) cin>>arr[i].first>>arr[i].second;
	dp[0][0]=0,dp[0][1]=0; ////init
	for(int i=1;i<=n;i++){
		int w=arr[i].first,t=arr[i].second;
		for(int j=m;j>=0;j--){            ////因为是优化省略了考虑第i个物品的维度,所以枚举j的时候要从大到小枚举。否则可能导致同一个物品被多次选择
			////不使用魔法
			dp[j][0]=min(dp[j][0],dp[max(j-w,0ll)][0]+t);
			dp[j][1]=min(dp[j][1],dp[max(j-w,0ll)][1]+t);
			////使用魔法
			dp[j][1]=min(dp[j][1],dp[max(j-2*w,0ll)][0]+t/2);
		}	
	}
	cout<<min(dp[m][0],dp[m][1]);
}

 

posted @ 2024-04-29 16:36  osir  阅读(22)  评论(0编辑  收藏  举报