西安网络赛e题

首先直接上一个最大流模板

然后在n<=1000的范围内打表(这题一定是有规律的为什么呢?因为是从小到大而且是只能是小连接大,而且有事1-n-1条件本身规律性就很强。)

然后我们注意到由于是异或运算首先考虑的是和2^k的关系,也就是说存在的规律应该是和2^k的相关。

然后一般打表就打出各项的差值和真正值就好了,观察下发现

2 5 2 三个数是成周期性变化的,然后每隔4个数会成一次突变,嗯如果这你表打小了的话规律就是这样了。但是当n=1000的时候发现在n=2^k的时候有会呈现一个不同的突变

所以有三种规律:对于差值:从第6项开始

1. 2 5 2呈现周期性变化。

2.如果一个n=2^k*乘上一个奇数 那么他的差值是f(2^k)+1的 f是一个映射f(x)=x^2+1

3.如果一个n恰好等于2^k的时候差值是 g(2^k)+1的 g又是一个映射具体规律看表.

这样我们阔以先预处理出f和g

然后看n的二进制上有多少个1消灭第3个规律

然后n/4消灭第一个规律

然后n每次除二看奇数有多少个消灭第二个规律

总的复杂度是log(n)的。

打表代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int INF = 1e9;
const int maxn = 1e3 + 5;
const int maxv = 1e6 + 7;
int head[maxv], cur[maxv], d[maxv], s, t, k, sum;
int n, m, dis[maxn];
struct node
{
	int v, w, next;
}edge[maxv];

void addEdge(int u, int v, int w)
{
	edge[k].v = v;
	edge[k].w = w;
	edge[k].next = head[u];
	head[u] = k++;
	edge[k].v = u;
	edge[k].w = 0;
	edge[k].next = head[v];
	head[v] = k++;

}

int bfs()
{
	memset(d, 0, sizeof(d));
	d[s] = 1;
	queue<int> q;
	q.push(s);
	while (!q.empty())
	{
		int u = q.front();
		if (u == t) return 1;
		q.pop();
		for (int i = head[u]; i != -1; i = edge[i].next)
		{
			int to = edge[i].v, w = edge[i].w;
			if (w && d[to] == 0)
			{
				d[to] = d[u] + 1;
				if (to == t) return 1;
				q.push(to);
			}
		}
	}
	return 0;
}

int dfs(int u, int maxflow)
{
	if (u == t) return maxflow;
	int ret = 0;
	for (int i = cur[u]; i != -1; i = edge[i].next)
	{
		int to = edge[i].v, w = edge[i].w;
		if (w && d[to] == d[u] + 1)
		{
			int f = dfs(to, min(maxflow - ret, w));
			edge[i].w -= f;
			edge[i ^ 1].w += f;
			ret += f;
			if (ret == maxflow) return ret;
		}
	}
	return ret;
}

int Dinic()
{
	int ans = 0;
	while (bfs() == 1)
	{
		memcpy(cur, head, sizeof(head));
		ans += dfs(s, INF);
	}
	return ans;
}

int main(void)
{
	int e;
	while (~scanf("%d", &e))
	{
		int pre = 0;
		for (int i = 2; i <= e; i++)
		{
			n = i;
			memset(head, -1, sizeof(head));
			s = 0, t = n - 1; k = 0, sum = 0;
			for (int i = 0; i < n; i++)
			{
				for (int j = i + 1; j < n; j++)
				{
					if (j == n - 1) dis[i] = i ^ j, sum += i ^ j;
					addEdge(i, j, i^j);
				}
			}
			int cur = Dinic();
			printf("%2d: %3d 差值:%3d\n", i, cur, cur - pre);
			pre = cur;
		}
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值