牛客网暑期ACM多校训练营(第二场)

 

Arun

链接:https://www.nowcoder.com/acm/contest/140/A
来源:牛客网
 

题目描述

White Cloud is exercising in the playground.
White Cloud can walk 1 meters or run k meters per second.
Since White Cloud is tired,it can't run for two or more continuous seconds.
White Cloud will move L to R meters. It wants to know how many different ways there are to achieve its goal.
Two ways are different if and only if they move different meters or spend different seconds or in one second, one of them walks and the other runs.

 

输入描述:

The first line of input contains 2 integers Q and k.Q is the number of queries.(Q<=100000,2<=k<=100000)
For the next Q lines,each line contains two integers L and R.(1<=L<=R<=100000)

输出描述:

For each query,print a line which contains an integer,denoting the answer of the query modulo 1000000007.

 

示例1

输入

复制

3 3
3 3
1 4
1 5

输出

复制

2
7
11

dp[i][j]存放的是到达第i个状态时最大的种类数,i代表当前的位置,0代表从i-1走到i,1代表从i-1跑到i。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
const int mod = 1e9 + 7;
#define ll long long
ll dp[N][2];
ll sum[N];
int q, k;
void inti()
{
    dp[0][0] = 1;
    for(int i = 1; i <= N - 5; i++)
    {
        dp[i][0] += dp[i - 1][1] + dp[i - 1][0];
        dp[i][0] %= mod;
        if(i - k >= 0)
        dp[i][1] += dp[i - k][0];
        dp[i][1] %= mod;
    }
    for(int i = 1; i <= N - 5; i++)
    {
        sum[i] = sum[i - 1] + dp[i][0] + dp[i][1];
        sum[i] %= mod;
    }
}
 
int main()
{
 
 
    scanf("%d %d", &q, &k);
    inti();
    while(q--)
    {
        int l, r;
        scanf("%d %d", &l, &r);
        printf("%lld\n", (sum[r] - sum[l - 1] + mod) % mod);
    }
    return 0;
}

 

Dmoney点击查看进入讨论693/2452 通过

链接:https://www.nowcoder.com/acm/contest/140/D
来源:牛客网
 

题目描述

White Cloud has built n stores numbered from 1 to n.
White Rabbit wants to visit these stores in the order from 1 to n.
The store numbered i has a price a[i] representing that White Rabbit can spend a[i] dollars to buy a product or sell a product to get a[i] dollars when it is in the i-th store.
The product is too heavy so that White Rabbit can only take one product at the same time.
White Rabbit wants to know the maximum profit after visiting all stores.
Also, White Rabbit wants to know the minimum number of transactions while geting the maximum profit.
Notice that White Rabbit has infinite money initially.

 

 

输入描述:

The first line contains an integer T(0<T<=5), denoting the number of test cases.
In each test case, there is one integer n(0<n<=100000) in the first line,denoting the number of stores.
For the next line, There are n integers in range [0,2147483648), denoting a[1..n].

输出描述:

For each test case, print a single line containing 2 integers, denoting the maximum profit and the minimum number of transactions.

 

示例1

输入

复制

1
5
9 10 7 6 8

输出

复制

3 4

dp[i][j]表示在i位置你可以获得的最大收益,cost[i][j],表示在状态dp[i][j]时的最小事物次数。

其中j=0表示你手中已经没有商品,j=1表示你手中有商品。

dp[i][0]=max(dp[i-1][1]+a[i],dp[i-1][0])。

dp[i][1]-max(dp[i-1][0]-a[i],dp[i-1][1])。

 

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll dp[100005][2];
ll a[100005],cost[100005][2];
int main()
{
    ll t,n;
    scanf("%lld", &t);
    while(t--)
    {
        scanf("%lld",&n);
        memset(dp,0,sizeof(dp));
        memset(cost,0,sizeof(cost));
        for(ll i=1;i<=n;i++)scanf("%d",&a[i]);
        dp[1][0]=0;dp[1][1]=-a[1];
        cost[1][0]=0;cost[1][1]=1;
        for(ll i=2;i<=n;i++)
        {
            if(dp[i-1][1]+a[i]>dp[i-1][0])
            {
                dp[i][0]=dp[i-1][1]+a[i];
                cost[i][0]=cost[i-1][1]+1;
            }
            else if(dp[i-1][1]+a[i]<dp[i-1][0])
            {
                dp[i][0]=dp[i-1][0];
                cost[i][0]=cost[i-1][0];
            }
            else
            {
                dp[i][0]=dp[i-1][0];
                cost[i][0]=min(cost[i-1][1]+1,cost[i-1][0]);
            }
            if(dp[i-1][0]-a[i]>dp[i-1][1])
            {
                dp[i][1]=dp[i-1][0]-a[i];
                cost[i][1]=cost[i-1][0]+1;
            }
            else if(dp[i-1][0]-a[i]<dp[i-1][1])
            {
                dp[i][1]=dp[i-1][1];
                cost[i][1]=cost[i-1][1];
            }
            else
            {
                dp[i][1]=dp[i-1][1];
                cost[i][1]=min(cost[i-1][0]+1,cost[i-1][1]);
            }
 
        }
        printf("%lld %lld\n",dp[n][0],cost[n][0]);
    }
    return 0;
}
Gtransform点击查看进入讨论229/1296 通过

我们求的答案肯定是一个连续的区间,所以二分答案,然后尺取法枚举左端点和右端点即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ff(l,r) for(ll i=l;i<=r;i++)
ll a[500005];
ll sum1[500005],sum2[500005];
ll x[500005];

ll ad1(ll l,ll r)
{
	return sum1[r]-sum1[l-1];
}
ll ad2(ll l,ll r)
{
	return sum2[r]-sum2[l-1];
}
ll n,T;

ll check(ll t)
{
	//cout<<t<<endl;
	//l左,r右,m中 
	for(ll l=1,m=1,r=1;l<=n;l++)
	{
		while(r<n&&ad1(l,r)<t) r++;
		while(m<n&&ad1(l,m)*2<t) m++;
		if(ad1(l,r)>=t&&(x[m]*ad1(l,m)-ad2(l,m)+ad2(m,r)-x[m]*ad1(m,r)-(ad1(l,r)-t)*(x[r]-x[m]))<=T)
		{
			return true;
		}
	}
	for(ll r=n,m=n,l=n;r>=1;r--)
	{
		while(l>1&&ad1(l,r)<t) l--;
		while(m>1&&ad1(m,r)*2<t) m--;
		if(ad1(l,r)>=t&&(x[m]*ad1(l,m)-ad2(l,m)+ad2(m,r)-x[m]*(ad1(m,r))-(ad1(l,r)-t)*(x[m]-x[l]))<=T)
		return true;
	}
	return false;
}
/*
2 3
1 2
2 3
*/

int main()
{
	scanf("%lld%lld",&n,&T);T/=2;
	ff(1,n) scanf("%lld",&x[i]);
	ff(1,n) scanf("%lld",&a[i]);
	ff(1,n)
    {
        sum1[i]=sum1[i-1]+a[i];
        sum2[i]=sum2[i-1]+a[i]*x[i];
    }
	ll l=1,r=sum1[n];
	while(l<r)
	{
		ll mid=(l+r+1)/2;
		if(check(mid)) 
			l=mid;
		else 
			r=mid-1;
	}
	printf("%lld\n",l);
	return 0;
}

 

Htravel点击查看进入讨论167/494 通过

题意:一棵树选择三条不相交路径,问最大权值和是多少。

思路:问一棵树的最大,最长这类问题一般都是动态规划。这题也不例外。我们用dp[i][j][k]表示以i为更节点的子树,已经选择了j条路径,其中与i相连的路径有k条。那么k最多可以为2,因为与i相连的两条节点可以看做一条结点,那么j最大自然是4了。

 

 

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
vector<ll> q[400016];
ll a[400016];
ll dp[400016][6][4];
void dfs(ll f,ll u)
{
    //当前节点 当前节点的子树已经找到几条 与他相连的有几条
    dp[u][0][0]=0;dp[u][1][1]=a[u];
    for(ll i=0;i<q[u].size();i++)
    {
        ll v=q[u][i];
        if(v==f) continue;
        dfs(u,v);
        for(ll j = 4; j >= 0; j--)
        {
            for(ll k =0;k<=j-1;k++)
            { 
                dp[u][j][2] = max(dp[u][j][2], dp[u][k][1] + dp[v][j - k][1]);
                dp[u][j][2] = max(dp[u][j][2], dp[u][k][2] + max(dp[v][j - k][0], max(dp[v][j - k + 1][2], dp[v][j - k][1])));
  
                dp[u][j][1] = max(dp[u][j][1], dp[u][k][0] + dp[v][j - k][1] + a[u]);
                dp[u][j][1] = max(dp[u][j][1], dp[u][k][1] + max(dp[v][j - k][0], max(dp[v][j - k + 1][2], dp[v][j - k][1])));
  
               
                dp[u][j][0] = max(dp[u][j][0], dp[u][k][0] + max(dp[v][j - k][0], max(dp[v][j - k + 1][2], dp[v][j - k][1])));
            }
        }
    }
}
int main()
{
    ll n;
    scanf("%lld",&n);
    for(ll i=1;i<=n;i++) scanf("%lld",&a[i]);   
    for(ll i = 0; i <= n; i++)
    for(ll j = 0; j < 6; j++)
        for(ll k = 0; k < 3; k++)
            dp[i][j][k] = -INF;
    for(ll i=1;i<n;i++)
    {
        ll x,y;
        scanf("%lld%lld",&x,&y);
        q[x].push_back(y);
        q[y].push_back(x);
    }
    dfs(1,1);
    printf("%lld\n", max(dp[1][3][0], max(dp[1][4][2], dp[1][3][1])));
     
    return 0;
}

 

I

car点击查看进入讨论534/1939 通过

链接:https://www.nowcoder.com/acm/contest/140/D
来源:牛客网
 

题目描述

White Cloud已经建立了从1到n的n个商店。
白兔想要按照从1到n的顺序访问这些商店。
编号为i的商店的价格为[i],表示白兔可以花费[i]美元购买产品或销售产品以获得[i]美元,当它在第i个商店时。
产品太重,因此白兔只能同时服用一种产品。
白兔想要知道访问所有商店后的最大利润。
此外,White Rabbit希望在确定最大利润的同时知道最少的交易数量。
请注意,白兔最初有无限的钱。

 

 

输入描述:

第一行包含整数T(0 <T <= 5),表示测试用例的数量。
在每个测试用例中,第一行中有一个整数n(0 <n <= 100000),表示存储的数量。
对于下一行,在[0,2147483648]范围内有n个整数,表示[1..n]。

输出描述:

对于每个测试用例,打印包含2个整数的单行,表示最大利润和最小事务数。

示例1

输入

复制

1
五
9 10 7 6 8

输出

复制

3 4

找规律的题目,多举几个例子发现没有障碍时答案是2n-(n%2)。

当我们加入障碍时,把那些行列去掉就行了。注意当n为奇数时,(n+1)/2行和(n+1)/2列都不能放。所以减多的要加回来。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int X[N], Y[N];
 
int main()
{
    int n, m;
    scanf("%d %d", &n, &m);
    for(int i = 1; i <= m; i++)
    {
        int x, y;
        scanf("%d %d", &x, &y);
        X[x] = 1;
        Y[y] = 1;
    }
    int k = n / 2;
    int ans = k * 4 + (n % 2);
    for(int i = 1; i <= n; i++)
    {
        if(X[i]) ans--;
    }
    for(int i = 1; i <= n; i++)
    {
        if(Y[i]) ans--;
    }
    if(n%2)
    {
        if(X[k + 1]) ans++;
        if(Y[k + 1]) ans++;
        if(X[k + 1] && Y[k + 1]) ans--;
    }
    printf("%d\n", ans);
    return 0;
}
farm点击查看进入讨论608/2846 通过

链接:https://www.nowcoder.com/acm/contest/140/J
来源:牛客网
 

题目描述

White Rabbit has a rectangular farmland of n*m. In each of the grid there is a kind of plant. The plant in the j-th column of the i-th row belongs the a[i][j]-th type.
White Cloud wants to help White Rabbit fertilize plants, but the i-th plant can only adapt to the i-th fertilizer. If the j-th fertilizer is applied to the i-th plant (i!=j), the plant will immediately die.
Now White Cloud plans to apply fertilizers T times. In the i-th plan, White Cloud will use k[i]-th fertilizer to fertilize all the plants in a rectangle [x1[i]...x2[i]][y1[i]...y2[i]].
White rabbits wants to know how many plants would eventually die if they were to be fertilized according to the expected schedule of White Cloud.

 

 

输入描述:

The first line of input contains 3 integers n,m,T(n*m<=1000000,T<=1000000)
For the next n lines, each line contains m integers in range[1,n*m] denoting the type of plant in each grid.
For the next T lines, the i-th line contains 5 integers x1,y1,x2,y2,k(1<=x1<=x2<=n,1<=y1<=y2<=m,1<=k<=n*m)

输出描述:

Print an integer, denoting the number of plants which would die.

 

示例1

输入

复制

2 2 2
1 2
2 3
1 1 2 2 2
2 1 2 1 1

输出

复制

3

区间染色问题一般都是需要二维树状数组或者线段树来维护。

本题目我们采用了二维树状数组的方法。把所有操作全部记录下来。然后每执行一次操作对所执行性的区间执行加一操作。

做完这些后,我们讨论染色的种类,从记录中删去每种染的颜色的种类,然后查询最开始等于这种颜色的格子的sum值有没有改变如果改变说明他被去其他颜色染过。查询完这类颜色后,我们在对操作进行复原。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define N 1000005
typedef pair<int,int> pll;
vector<pll> kind[N]; //颜色为n的坐标
vector<pll> op1[N],op2[N]; //操作
vector<int> t[N];
int n,m,w;
void read(int &x)
{
    char c = getchar(); x = 0;
    while(c < '0' || c > '9') c = getchar();
    while(c <= '9' && c >= '0') x = x*10+c-48, c = getchar();
}
 
int bit(int x)
{
    return x&-x;
}
void add(int x, int y, int w)
{
    for (int i = x; i <= n; i +=bit(i))
        for (int j = y; j <= m; j += bit(j))
            t[i][j] += w;
 
}
 
int Sum(int x,int y)
{
    int res = 0;
    for (int i = x; i; i -= bit(i))
        for (int j = y; j; j -=  bit(j))
            res += t[i][j];
    return res;
}
void add_1(int x1,int y1,int x2,int y2,int w)
{
    add(x1,y1,w);
    add(x1,y2+1,-w);
    add(x2+1,y1,-w);
    add(x2+1,y2+1,w);
}
int main()
{
    read(n);read(m);read(w);
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=m; j++)
        {
            int x;read(x);
            kind[x].push_back(pll(i,j));
        }
    }
    for(int i=0; i<=n; i++)
    {
        t[i].clear();
        for(int j=0; j<=m; j++)
            t[i].push_back(0);
    }
    while(w--)
    {
        int q,p,x,y,z;read(q);read(p);read(x);read(y);read(z);
        add_1(q,p,x,y,1);
        op1[z].push_back(pll(q,p));
        op2[z].push_back(pll(x,y));
    }
    int ans=0;
    for(int i=1; i<=n*m; i++)
    {
        for(int j=0; j<op1[i].size(); j++)
            add_1(op1[i][j].first,op1[i][j].second,op2[i][j].first,op2[i][j].second,-1);
        for(int j=0; j<kind[i].size(); j++)
            if(Sum(kind[i][j].first,kind[i][j].second)>0)
            {
                //printf("%d %d %d\n",i,kind[i][j].first,kind[i][j].second);
                ans++;
            }
        for(int j=0; j<op1[i].size(); j++)
            add_1(op1[i][j].first,op1[i][j].second,op2[i][j].first,op2[i][j].second,1);
    }
    printf("%d\n",ans);
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值