【无标题】

E. Black and White Tree 未补
E. Purple Crayon 未补
E1. Cats on the Upgrade (easy version) 未补
整体二分 未补
D2. Game on Sum 未补
D. Flipping Range 未补

牛客练习赛95 gcd代码
牛客练习赛95 Painting Fences代码
E. New School代码
E. Middle Duplication代码






就枚举r从0-k,然后算出那个式子的最小值的最大值,最小值是看b的最大值,因为b如果可以染x个节点,那么可以把一个树砍掉根节点也是可以的,那就可以染x-1个节点,所以要看b可以染的最大值最大值采取贪心,根据每个节点的贡献来贪。
假设一棵树的最大深度子节点是x那么这棵树的其它节点被选之前一定要选x,所以其他节点的贡献就从新开始算,这样算这真好,原本还想线段树+dfs序查询区间最小值和标记区间减1,但是看其他人代码也不像,所以想到这玩意,不过好像也可以另一种贪心也是对的,不知道咋证明,看代码吧。。。

int siz[N], deep[N], son[N];
vector<int>G[N], ans;

int dfs(int u, int fa, int d)  // siz是子树的最大深度,son 是子树中有最大深度的那颗子树;
{
	if(G[u].size() == 1 && G[u][0] == fa) return siz[u] = d;
	for(auto x : G[u])
	{
		if(x == fa) continue;
		siz[u] = max(siz[x], dfs(x, u, d+1));
		if(siz[son[u]] < siz[x]) son[u] = x;
	}
	return siz[u];
}

void dfs1(int u, int fa)
{
	deep[son[u]] = deep[u] + 1;
	son[u] ? dfs1(son[u], u) : ans.push_back(deep[u]);
	for(auto x : G[u])
	{
		if(x == fa||x == son[u]) continue;
		deep[x] = 1;
		dfs1(x, u);
	}
}
int main() 
{
	int n, k;
	scanf("%d%d", &n, &k);
	for(int i = 2;i <= n;i ++) 
	{
		int u, v;
		scanf("%d%d", &u, &v);
		G[u].push_back(v); G[v].push_back(u);
	}
	deep[1] = 1; dfs(1, 0, 0); dfs1(1, 0);
	sort(ans.begin(), ans.end(), greater<int>());
	int b = n;
	LL x = -0x3f3f3f3f3f3f3f3f;
	for(int i = 0;i < k;i ++)
	{
		if(i < ans.size()) b -= ans[i];
		int temp = min(b, n>>1);
		x = max(x, (LL)(temp+i+1-n)*(temp-i-1));
	}
	cout<<x<<endl;
	return 0;
} 
// 另一种贪心。
// 按照字数大小贪心。
void dfs(int u, int fa)
{
	siz[u] = 1;
	for(auto x : G[u])
	{
		if(x == fa) continue;
		dfs(x, u);
		siz[u] += siz[x];
		if(siz[son[u]] < siz[x]) son[u] = x;
	}
}


…期望线性,E(ans) = ∑ i = 2 n \sum_{i=2}^{n} i=2n E(a[i] ≠ a[i-1]) = ∑ i = 2 n \sum_{i=2}^{n} i=2n 1 - E(a[i] = a[i-1]);
第一个等号就没想到

void add(int &u, LL v){u = (u+v)%mod;return ;}
void mull(int &u, LL v){u = u*v%mod;return ;}

int qsm(LL u, int v){LL ans = 1;for(;v;v>>=1,u=u*u%mod)if(v&1)ans=ans*u%mod;return ans;}
int inv(int u){return qsm(u, mod-2);}
map<pair<int,int>, bool>ma; 
int c[N], x[N], y[N], num[N]; // c[i] i和i-1相同的情况,num[i] i可选的数量; 

int v(int i){return mod-(LL)c[i]*inv((LL)num[i-1]*num[i]%mod)%mod;}  // c/num/num; 

int main() 
{
	int n, m, q;
	scanf("%d%d%d", &n, &m, &q);
	int ans = n;
	for(int i = 1;i <= n;i ++) num[i] = m;
	for(int i = 2;i <= n;i ++) c[i] = m, add(ans, v(i));	
	cout<<ans<<endl;
	for(int i = 1;i <= q;i ++)
	{
		int f, id;
		scanf("%d", &f);
		if(f&1){
			scanf("%d%d", x+i, y+i);
			bool a = ma[{x[i]-1, y[i]}], b = ma[{x[i], y[i]}], d = ma[{x[i]+1, y[i]}];
			add(ans, -v(x[i])), add(ans, -v(x[i]+1)), num[x[i]] --;
			if(x[i] > 1) c[x[i]] -= (!a&&!b), add(ans, v(x[i]));
			if(x[i] < n) c[x[i]+1] -= (!b&&!d), add(ans, v(x[i]+1)); 
		}
		else{
			scanf("%d", &id), x[i] = x[id], y[i] = y[id];
			bool a = ma[{x[i]-1, y[i]}], b = ma[{x[i], y[i]}], d = ma[{x[i]+1, y[i]}];
			add(ans, -v(x[i])), add(ans, -v(x[i]+1)), num[x[i]] ++;
			if(x[i] > 1) c[x[i]] += (a^b), add(ans, v(x[i]));
			if(x[i] < n) c[x[i]+1] += (b^d), add(ans, v(x[i]+1)); 
			
		}
		ma[{x[i], y[i]}] = 1 - ma[{x[i], y[i]}];

        add(ans, mod);
		printf("%d\n", ans);
	}

	return 0;
} 


∑ i = 1 n ∏ j = 1 n R [ i ] i − L [ i ] − 1 i \sum_{i=1}^n \prod_{j=1}^n{\frac{R[i]}{i}-\frac{L[i]-1}{i}} i=1nj=1niR[i]iL[i]1 交换顺序,再分块再前缀乘

const int N = 3e5+10, mod = 998244353; // 1e9+7  998244353
void add(int &u, LL v){u = (u+v)%mod;return ;}
void mull(int &u, LL v){u = u*v%mod;return ;}

int qsm(LL u, int v){LL ans = 1;for(;v;v>>=1,u=u*u%mod)if(v&1)ans=ans*u%mod;return ans;}
int inv(int u){return qsm(u, mod-2);}
int st[N], in[N], ze[N];
int main() 
{
	int n;
	scanf("%d", &n);
	for(int i = 0;i <= 3e5;i ++) st[i] = 1, in[i] = inv(i);
	for(int i = 1;i <= n;i ++)
	{
		int x, y;
		scanf("%d%d", &x, &y);
		x --;
		st[y+1] = 0;
		for(int l = 1, r;l <= y;l = r + 1)
		{
			r = min(y/(y/l) , l<=x?x/(x/l) : N);
		    int t = y/l-x/l;
            if(t) mull(st[l], t), mull(st[r+1], in[t]);
            else  ze[l] ++, ze[r+1] --;  // 可能某一段是0但是后面不是0 
		}
	}
	int ans = 0;
	for(int i = 1;i <= 3e5;i ++)
		mull(st[i], st[i-1]), add(ze[i], ze[i-1]), add(ans, ze[i] ? 0 : st[i]);
	cout<<ans<<endl;
	return 0;
} 



先贪心,每组一个老师,然后有两种思路
 一种是分开来看,那就是第一大的老师指导第一大的同学,第二对第二…, 看一组去掉一个数后应该在哪里,这时候就要预处理一段区间统一往右或往左是否可行,代码如下。
 第二种是放到一起,m和m个PLI (pair<LL,int>)都放到一个数组里面然后排序按照平均值,老师平均值就是它本身,平均值相同老师较大,然后从后往前遍历,是学生那样-1,是老师那样+1,这样对不考虑变化的情况,是否可行就是m个组都大于等于0,然后改变的话就是区间最小值是否大于一个数(0/1),大概这种方法是这种思路,这种好像只用个st表,没写.

bool L[N], R[N];   // L,R 是不移动的情况下 1-i对1-i是否可行 和 i-m对i-m是否可行。 
int a[N], l[N], r[N]; // l,r 是左移动或右移动的前缀和; 
vector<int>v[N];
struct point{
	LL x, y;
	friend bool operator < (const point a, const point c){return a.x*c.y < a.y*c.x;}
}c[N];

int main() 
{
	int t;
	scanf("%d", &t);
	for(int _ = 1;_ <= t; _ ++)
	{
		int n, m;
		scanf("%d%d", &n, &m);
		for(int i = 1;i <= n;i ++) scanf("%d", a+i);
		sort(a+1, a+n+1);
		for(int i = 1;i <= m;i ++) a[i] = a[i+n-m];
		for(int i = 1;i <= m;i ++)
		{
			int len, t; 
			scanf("%d", &len);
			c[i].y = len; c[i].x = 0; v[i].clear();
			for(int j = 1;j <= len;j ++)
			{
				scanf("%d", &t);
				v[i].push_back(t); c[i].x += t;
			}
		}
		sort(c+1, c+m+1);
		
		L[0] = R[m+1] = 1; // 预处理 
		for(int i = 1;i <= m;i ++) 
		 	(l[i] = 1LL*a[i-1]*c[i].y >= c[i].x), 
			(r[i] = 1LL*a[i+1]*c[i].y >= c[i].x),
			L[i] = R[i] = 1LL*a[i]*c[i].y >= c[i].x;
		for(int i = 1;i <= m;i ++) L[i] &= L[i-1], l[i] += l[i-1], r[i] += r[i-1];
		for(int i = m;i >= 1;i --) R[i] &= R[i+1];

		for(int i = 1;i <= m;i ++) 
		{
			LL sum = 0;
			for(auto x : v[i]) sum += x;
			int siz = v[i].size(), pos = lower_bound(c+1, c+m+1, point{sum, siz}) - c;  
			for(auto x : v[i])
			{
				int k = upper_bound(c+1, c+m+1, point{sum-x, siz-1}) - c - 1;  // 这里面有点玄学。。。。 
				bool f = 1;
				if(k < pos){ 
					k ++;
					f = (r[pos-1]-r[k-1] ==  pos-1-k+1)&L[k-1]&R[pos+1];
				}
				else if(k >= pos) f = (l[k]-l[pos] == k-pos)&L[pos-1]&R[k+1];
				printf("%d", f&(1LL*a[k]*(siz-1) >= sum-x));
			}
		}
		puts("");
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李昌荣。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值