2018牛客多校第二场

C

将问题转化为求凸包

#include 
using namespace std;
typedef long long ll;

const double esp=1e-10;
const int MAXN=100000+5;
struct Point{
    int x,y,id;
    Point(int _x=0,int _y=0,int _id=0){
        x=_x,y=_y,id=_id;
    }
    bool operator <(const Point &b)const{
        if(x==b.x)  return id>1;
                        if(K(p[i],p[Stack[m]])1&&((p[i]-p[Stack[top-2]])^(p[Stack[top-1]]-p[Stack[top-2]]))<=0)
                    top--;
                Stack[top++]=i;
            }
        }
    }
}c1,c2;
int main(){
    int n,m,x,y;
    scanf("%d",&n);
    for(int i=0;i

 

G

思维+二分

#include 
using namespace std;
 
typedef long long LL;
const int maxn = 5e5+1000;
LL N,T;
LL x[maxn],a[maxn],sum[maxn],sumd[maxn];
//  sum[i] 表示到第i个点,共有多少product
//  sumd[i] 表示到第i个点,把这些点上所有的货物运送到0点需要的cost
//  把[l,r] 区间内的货物移到 l 则  ca1(l,r) = sumd[r]-sumd[l-1]-(sum[r]-sum[l-1])*d[l]
//  把[l,r] 区间内的货物移到 r 则  ca2(l,r) = (sum[r]-sum[l-1])*(x[r]-x[l])-ca1(l,r)
LL  ca2(LL l,LL r){
    return  sumd[r]-sumd[l-1]-(sum[r]-sum[l-1])*x[l];
}
LL  ca1(LL l,LL r){
    return  (sum[r]-sum[l-1])*(x[r]-x[l])-ca2(l,r);
}
bool judge(LL mid){
  
    LL l ,r,i;
    LL mid2 = mid/2+1;
    // 假设l 为必选的位置,没有完全转移的箱子是 r
     l = 1,r = 1, i = 1;
    while(1){
        while( r <= N&& sum[r]-sum[l-1] < mid) r++;// 不足mid就增加r
        while(i <= N&&sum[i]-sum[l-1] < mid2)  i++;// 求区间货物中位数所在的位置
         if(r > N|| i > r) break;// 如果找不到符合条件的break出去
        LL plus = sum[r]-sum[l-1]-mid;// 右端点可能会多plus个product
        if((ca1(l,i)+ca2(i,r)-(x[r]-x[i])*plus )<= T) return true;
        l++;// 这一个左端点不行,换下一个
    }
    // 假设r 集装箱内所有物品都已经转移,而l可能没有转移完
    l = r = i = N;
    while(1){
        while(l >= 1&& sum[r]-sum[l-1] < mid) l--;
        while(i >= 2&& sum[r]-sum[i-1] < mid2) i--;
        if(i < l||l < 1)
           break;
        LL plus = sum[r]-sum[l-1]-mid;// 左端点可能多plus个product
        if(ca1(l,i)+ca2(i,r)-(x[i]-x[l])*plus <= T) return true;
        r--;// 这个左端点不行,换下一个
    }
    return false;
}
int main(void)
{
    scanf("%lld %lld",&N,&T),T>>=1;
    for(int i = 1;i <= N; ++i)
      scanf("%lld",&x[i]);
    LL M = 0;
    for(int i = 1;i <= N; ++i)
       scanf("%lld",&a[i]),sum[i] = sum[i-1]+a[i],M = max(M,a[i]),sumd[i] = sumd[i-1]+a[i]*x[i];
  
    LL l = M,r = sum[N];
  
    while(l <= r){
      LL mid = l+(r-l)/2;
      if(judge(mid))
         l = mid+1;
      else
         r = mid-1;
    }
    printf("%lld",r);
    return 0;
}

H

树形dp

#include
#define ll long long
using namespace std;
const int maxn=4e5+10;
const ll mod=1e9+7;
const int maxm=1e6+10;
const double eps=1e-7;
const ll inf=(ll)1e13;
struct Edge{
    int u,v,next;
}edge[maxm];
int head[maxn];
int tot=0;
void init(){
    memset(head,-1,sizeof(head));
    tot=0;
}
void addedge(int u,int v){
    edge[tot]=Edge{u,v,head[u]};
    head[u]=tot++;
}
int n;
ll a[maxn];
ll dp[maxn][8][4];
//dp(i,j,k)表示i子树上有j条链,i节点上有k条链的结果
void dfs(int u,int fa){
    dp[u][0][0]=0;
    //啥都没有,肯定是0了
    dp[u][1][1]=a[u];
    //只有自己一个节点作为一条链的答案
    for (int i=head[u];~i;i=edge[i].next){
        int v=edge[i].v;
        if (v==fa) continue;
        dfs(v,u);
        for (int j=4;j>=0;j--){
            for (int k=j-1;k>=0;k--){
                dp[u][j][2]=max(dp[u][j][2],dp[u][k][1]+dp[v][j-k][1]);
                //其他子树上提供了k条链,并且有一条在u上,那么剩下的j-k条由v提供,并提供一条u-v的链
                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])));
                //其他子树上提供了k条链,并且有两条在u上,那么剩下的j-k条由v提供,不提供u节点到v的链
                //这时候v节点的dp值取0条连在v上,一条连在v上,两条连在v上的dp的最大值
                //取两条的时候,数目要+1
                dp[u][j][1]=max(dp[u][j][1],dp[u][k][0]+dp[v][j-k][1]+a[u]);
                //其他子树上提供了k条链,并且有一条在u上,那么剩下的j-k条由v提供,并提供一条u-v的链
                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])));
                //其他子树上提供了k条链,并且有一条在u上,那么剩下的j-k条由v提供,不提供u节点到v的链
                //这时候v节点的dp值取0条连在v上,一条连在v上,两条连在v上的dp的最大值
                //取两条的时候,数目要+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])));
                //其他子树上提供了k条链,并且没有在u上,那么剩下的j-k条由v提供,不提供u节点到v的链
                //这时候v节点的dp值取0条连在v上,一条连在v上,两条连在v上的dp的最大值
                //取两条的时候,数目要+1
            }
        }
    }
}
int main(){
    scanf("%d",&n);
    for (int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
    }
    init();
    for (int i=1;i

I

#include 
#include 
#include 
#include 
using namespace std;
int a[100005];
int b[100005];
int main(){
    int n,m;
    while(~scanf("%d%d",&n,&m)){
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        int ans=2*n-n%2;
        int f=0;
        for(int i=1;i<=m;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            if(n&1&&(x==n/2+1||y==n/2+1))
                f=1;
            if(a[x]==0){
                ans--;
                a[x]=1;
            }
            if(b[y]==0){
                ans--;
                b[y]=1;
            }
        }
        ans+=f;
        printf("%d\n",ans);
    }
    return 0;
}

J

get两个知识点:

1、随机化过题

2、如果有Q次修改区间值的操作,如何快速求出修改后每个位置的值

 

随机化的话,首先,对于这题,我们有这么一个想法:修改后的值 = 修改次数 * 初始值,那么这颗植物是很有可能活下来的。显然,直接这么写用脚都能hack掉,比如如果 8 = 4 + 4,那么显然也可以有 8 = 2 + 6, 那么怎么办?随机打乱一下,不妨设4 -> 6, 2 - >3, 6 -> 5,那么上面就变成了 12 = 6 + 6, 8 = 3 + 5,大大降低了被hack的几率。

 

对于一维的来说,[L,R]  加上k等价于 a[L] += k, a[R + 1] -= k,然后累加之后就是改变了多少值,再加上原先的值就是答案。理由如下,因为它是求的前缀和,那么对于L之后的一定都要加上k,R之后的就不能再加了,所以要减去。二维的话也可以类似的推广过去。

#include 
using namespace std;

typedef long long ll;
const int N = 2002000;

ll mp[N], g[N], change[N], vis[N];

int main(){
	int n, m, t;
	scanf("%d %d %d", &n, &m, &t);
	for(int i = 1; i <= n * m; i ++){
		mp[i] = i;
	}
	random_shuffle(mp + 1, mp + n * m + 1);
	for(int i = 1; i <= n; i ++){
		for(int j = 1; j <= m; j ++){
			scanf("%lld", &g[i * m + j]);
			g[i * m + j] = mp[g[i * m + j]];
		}
	}
	int x1, y1, x2, y2, k;
	while(t --){
		scanf("%d %d %d %d %d", &x1, &y1, &x2, &y2, &k);
		k = mp[k];
		change[x1 * m + y1] += k, change[(x2 + 1) * m + y2 + 1] += k;
		change[(x2 + 1) * m + y1] -= k, change[x1 * m + y2 + 1] -= k;
		vis[x1 * m + y1] ++, vis[(x2 + 1) * m + y2 + 1] ++;
		vis[(x2 + 1) * m + y1] --, vis[x1 * m + y2 + 1] --;
	}
		int tot = 0;
		for(int i = 1; i <= n; i ++){
			for(int j = 1; j <= m; j ++){
				change[i * m + j] += change[(i - 1) * m + j] + change[i * m + j - 1] - change[(i - 1) * m + j - 1];
				vis[i * m + j] += vis[(i - 1) * m + j] + vis[i * m + j - 1] - vis[(i - 1) * m + j - 1];
				if(change[i * m + j] != vis[i * m + j] * g[i * m + j])
					tot ++;
			}
		}
		printf("%d\n", tot);
		return 0;
	}

你可能感兴趣的:(2018牛客多校第二场)