牛客 2018 暑假多校训练第二场

https://www.nowcoder.com/acm/contest/140#question

A

题意:

白云可以走[L,R]米,每秒只有两种走法,走1米或者k米。求有几种走法。

思路:简单dp,很像以前那个入门dp,走台阶的问题,求出dp[i][j]:走到i位置前一步走了1米(j==0)前一步走了k米(j==1).的种类数,很简单,注意long long就行

代码:

#include<bits/stdc++.h>
#define mod 1000000007
using namespace std;
long long n,k,L,R,dp[100005][2],sum[100005];
int main()
{
    scanf("%lld%lld",&n,&k);
    for(int i=1;i<k;i++)
    {
        dp[i][0]=1;
        dp[i][1]=0;
        sum[i]=sum[i-1]+dp[i][0]+dp[i][1];
    }
    dp[0][0]=1;
    for(int i=k;i<=100000;i++)
    {
        dp[i][0]=(dp[i-1][0]+dp[i-1][1])%mod;
        dp[i][1]=dp[i-k][0];
        sum[i]=(sum[i-1]+dp[i][1]+dp[i][0])%mod;
    }
    while(n--)
    {
        scanf("%lld%lld",&L,&R);
        printf("%lld\n",(sum[R]-sum[L-1]+mod)%mod);
    }

}

D

题意:n个店铺,每个店铺买入卖出的价格给出,成本无限多,每次白云手里最多拿一件东西,求最大利润下的最小交易数量 

思路:这也是一道水题,画画图分析一下,是个贪心,就是所有递增序列左端点买入,右端点卖出。找连续递增子序列就可以,最后注意一下最后一个数的处理就行了

代码:

#include<bits/stdc++.h>
#define inf 800000000
#define ll long long
#define mod 1000000007
using namespace std;

ll a[100010];

int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        int i,n;
        bool f=0;
        ll now=0,cnt=0;
        cin>>n;
        for(i=0;i<n;i++)
        {
            cin>>a[i];
        }
        a[n]=0;
        for(i=0;i<n;i++)
        {
            if(a[i]<a[i+1]&&!f)
            {
                now-=a[i];
                cnt++;
                f=true;
            }
            else if(a[i]>a[i+1]&&f)
            {
                now+=a[i];
                cnt++;
                f=false;
            }
        }
        cout<<now<<" "<<cnt<<endl;
    }
}

I

扫描二维码关注公众号,回复: 2346481 查看本文章

题意:[n,n]的矩阵,从边缘往另一个方向有行驶的车。车的速度相同,给m个坏点,求最多安排几辆车,车互相之间不能撞车,并且不能走过坏点。

思路:对于无坏点的各个矩阵算最大车辆数,找规律得,n是偶数,最多安排2*n辆,n为奇数,最多安排2(n-1)辆。就是每行每列都会安排上一辆车,然后奇数的时候,中间的一行一列只能安排一辆车,然后对于坏点记录其影响的行列,最后判断一共影响了几行几列。。奇数时,中间的行列要特殊考虑

(PS:下面是队友的代码,跟自己的思路有出入,但差别不大,就不敲了)

代码:

#include<bits/stdc++.h>
#define inf 800000000
#define ll long long
#define mod 1000000007
using namespace std;

bool delx[100005],dely[100005];
int main()
{
    int cnt=0;
    int n,m;
    bool f=0;
    cin>>n>>m;
    if(n%2)
    {
        while(m--)
        {
            int x,y;
            cin>>x>>y;
            if(x==y&&x==(n+1)/2&&!f)
            {
                cnt++;
                f=1;
            }
            else
            {
                if(!delx[x]&&x!=(n+1)/2)
                {
                    cnt++;
                    delx[x]=1;
                }
                if(!dely[y]&&y!=(n+1)/2)
                {
                    cnt++;
                    dely[y]=1;
                }
                if(!delx[x]&&x==(n+1)/2)
                {
                    delx[x]=1;
                }
                if(!dely[y]&&y==(n+1)/2)
                {
                    dely[y]=1;
                }
            }
        }
        if(delx[(n+1)/2]&&dely[(n+1)/2]&&!f)
        {
            cnt++;
        }
    }
    else
    {
        while(m--)
        {
            int x,y;
            cin>>x>>y;


                if(!delx[x])
                {
                    cnt++;
                    delx[x]=1;
                }
                if(!dely[y])
                {
                    cnt++;
                    dely[y]=1;
                }
        }
    }
    int res;
    if(n%2)
    {
        res=2*(n-1)+1-cnt;
    }
    else
    {
        res=2*n-cnt;
    }
    cout<<res<<endl;
}

G

题意:数轴上n个集装箱,第i个集装箱位于坐标x[i],有a[i]件货物

现在把集装箱进行一些移动,求所有货物移动总距离不超过T/2的情况下做多能把多少个集装箱移到同一个位置?

思路:看了题解,然后摸了很久的标称终于弄懂了,标称没有注释,,真的好难理解。。反正这就是个二分,感觉还有dp的思想,check()种用到了i跟i-1的关系,所以只需要找1集装箱的具体位置就可以,后面的都可以从i-1转移到i,详细见代码,,注释的十分清楚了。。

代码

#include<bits/stdc++.h>

#define gs(c) (c < '0' || c > '9')
#define gc(c) c = getchar()
#define getint() ({ int w = 0; char gc(c); while (gs(c)) gc(c); while (!gs(c)) w = w*10+c-'0', gc(c); w; })
#define d(i, j) (int64)(x[j] - x[i])

using namespace std;

const int N = 500050;

typedef long long int64;

int n, x[N], a[N];
int64 T, s[N];

int64 sum(int l, int lc, int r, int rc) //集装箱l的第lc个物品到集装箱r的第rc-1个物品一共有多少物品
{
	return l == r? rc - lc: s[r - 1] - s[l] + a[l] - lc + rc;
}
bool check(int64 need) {
	int l = 1, lc = 1, r = n + 1, rc = 1;
	//从集装箱l的lc个物品开始转移,need个物品,到及集装箱r的rc-1,位置,rc位置已将是第need+1个物品了,不移。
	int64 cur = 0, sa = 0;//从第一个集装箱第一个物品开始移都移到第一个集装箱(l=1;lc=1)查找{r,rc},并计算这时最多移的个数
	for (int i = 1; i <= n; ++i) {
		if (sa + a[i] <= need) sa += a[i], cur += d(1, i) * a[i];
		else { r = i, rc = need - sa + 1, cur += d(1, i) * (rc - 1); break; }
	}
	if (cur <= T) return 1;

	for (int i = 2; i <= n; ++i)
	 {
		cur += d(i - 1, i) * (sum(l, lc, i, 1) - sum(i, 1, r, rc));//从1点的第一个物品开始的need个物品移到集装箱i的花费,集装箱i左面的从i-1移到i,集装箱i及右面的要原路返回到i。
		while (r <= n && d(l, i) > d(i, r))//能往右移
            {
			int z = min(a[l] - lc + 1, a[r] - rc + 1);//集装箱l选的移到r的剩余空间,最多移的个数
			cur += (d(i, r) - d(l, i)) * z;//移完后的花费
			if (lc += z, lc > a[l]) ++l, lc = 1;//l选的小,则l集装箱一个都没选,转到下一个集装箱
			if (rc += z, rc > a[r]) ++r, rc = 1;//r剩余的空间小,r集装箱选满,转到下一个集装箱
            }
		if (cur <= T) return 1;
	}
	return 0;
}
int main() {
	cin>>n>>T;
	assert(1<=n&&n<=500000);
	assert(1<=T&&T<=1e18);
	T /= 2;
	for (int i = 1; i <= n; ++i) x[i] = getint(),assert(1<=n&&n<=n),assert(i==1||x[i]>x[i-1]);
	for (int i = 1; i <= n; ++i) a[i] = getint(),assert(0<=a[i]&&a[i]<=1e4), s[i] = s[i - 1] + a[i];

	int64 ll = 0, rr = s[n];//二分答案,做多能转移的货物
	while (ll < rr) {
		int64 mm = (ll + rr + 1) >> 1;
		if (check(mm)) ll = mm;
		else rr = mm - 1;
	}
	cout<<ll<<endl;
}
/*
4 13
1 9 11 13
3 100 2 1
*/

猜你喜欢

转载自blog.csdn.net/qq_37868325/article/details/81151568