• NOI2010Day1


    T1 能量采集

    显然对于每个点采集时(k = gcd(i, j) - 1), 则

    [ans = sum_{i = 1}^{n}sum_{j = 1}^{m}(2 * gcd(i, j) - 1) \ ans = 2 * (sum_{i = 1}^{n}sum_{j = 1}^{m}gcd(i, j)) - n * m \ 欧拉反演得 \ ans = 2 * (sum_{d = 1}^{n}phi(d)lfloorfrac{n}{d} floorlfloorfrac{m}{d} floor) - n * m ]

    #include<bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    #define N 100005
    
    int n, m, prime[N], cnt = 0;
    
    ll phi[N];
    
    bool isprime[N];
    
    void Init(int n)
    {
    	isprime[1] = 1;
    	phi[1] = 1;
    	for(int i = 2; i <= n; i++)
    	{
    		if(!isprime[i]) prime[++cnt] = i, phi[i] = i - 1;
    		for(int j = 1; j <= cnt && i * prime[j] <= n; j++)
    		{
    			isprime[i * prime[j]] = 1;
    			if(i % prime[j] == 0)
    			{
    				phi[i * prime[j]] = phi[i] * prime[j];
    				break;
    			}
    			phi[i * prime[j]] = phi[i] * phi[prime[j]];
    		}
    	}
    	for(int i = 2; i <= n; i++) phi[i] += phi[i - 1];
    }
    
    int main()
    {
    	cin >> n >> m;
    	if(n > m) swap(n, m);
    	Init(n);
    	ll ans = 0;
    	for(int l = 1, r; l <= n; l = r + 1)
    	{
    		r = min(n / (n / l), m / (m / l));
    		ans += (phi[r] - phi[l - 1]) * (n / l) * (m / l);
    	}
    	printf("%lld
    ", ans * 2 - 1ll * n * m);
    	return 0;
    }
    

    T2 超级钢琴

    对每个点找出范围里的最大值,然后每次取完之后把两边两段加入,在堆中按区间最大值排序取k个即可。

    #include<bits/stdc++.h>
    
    using namespace std;
    
    #define N 500005
    typedef long long ll;
    
    int n, k, L, R;
    
    ll a[N];
    
    int st[20][N];
    
    int Log2(int x) {return log(x) / log(2);}
    
    int query(int l, int r)
    {
    	int len = log2(r - l + 1);
    	return (a[st[len][l]] >= a[st[len][r - (1 << len) + 1]]) ? st[len][l] : st[len][r - (1 << len) + 1];
    }
    
    struct point
    {
    	int o, l, r, val;
    
    	bool operator < (const point &s) const
    	{
    		return a[val] -  a[o - 1] < a[s.val] - a[s.o - 1];
    	}
    };
    
    priority_queue <point> pq;
    
    int main()
    {
    	scanf("%d%d%d%d", &n, &k, &L, &R);
    	for(int i = 1; i <= n; i++) scanf("%lld", &a[i]);
    	for(int i = 2; i <= n; i++) a[i] += a[i - 1];
    	for(int i = 1; i <= n; i++) st[0][i] = i;
    	for(int i = 1; i <= 19; i++)
    		for(int j = 1; j <= n - (i << 1) + 1; j++)
    		{
    			if(a[st[i - 1][j]] >= a[st[i - 1][j + (1 << i - 1)]]) st[i][j] = st[i - 1][j];
    			else st[i][j] = st[i - 1][j + (1 << i - 1)];
    			// cout << i << ' ' << j << ' ' << a[st[i][j]] << endl;
    		}
    	for(int i = 1; i <= n; i++)
    	{
    		int l = i + L - 1, r = min(i + R - 1, n);
    		if(l > n) break;
    		pq.push((point){i, l, r, query(l, r)});		
    	}	
    	ll ans = 0;
    	while(k--)
    	{
    		point u = pq.top();
    		pq.pop();
    		// cout << u.o << ' ' << u.val << endl;
    		ans += a[u.val] - a[u.o - 1];
    		int x = u.val;
    		if(u.l <= x - 1) pq.push((point){u.o, u.l, x - 1, query(u.l, x - 1)});
    		if(x + 1 <= u.r) pq.push((point){u.o, x + 1, u.r, query(x + 1, u.r)});
    	}
    	printf("%lld
    ", ans);
    	return 0;
    }
    

    T3 海拔

    首先发现取值只会是0或1, 然后可知两者都会只有一个联通块,体力消耗就是两个联通块中间连着的那些边。所以起点和终点的最小割就是答案。平面图转对偶图求一求就好了

    #include<bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    #define N 350005
    
    int n, head[N], nxt[N << 2], to[N << 2], cnt = 0;
    
    ll val[N << 2];
    
    void add(int x, int y, ll z)
    {
    	cnt++;
    	to[cnt] = y, val[cnt] = z, nxt[cnt] = head[x], head[x] = cnt;
    }
    
    ll dis[N];
    
    bool vis[N];
    
    struct point
    {
    	int x; ll dis;
    
    	bool operator < (const point &o) const 
    	{
    		return dis > o.dis;
    	}
    };
    
    priority_queue <point> q;
    
    int s = 0, t;
    
    ll ans = 0;
    
    void dij()
    {
    	memset(dis, 0x3f, sizeof(dis));
    	dis[s] = 0;
    	q.push((point){s, 0});
    	while(!q.empty())
    	{
    		point u = q.top(); q.pop();
    		int x = u.x;
    		if(vis[x]) continue;
    		vis[x] = 1;
    		for(int p = head[x]; p; p = nxt[p])
    		{
    			int v = to[p];
    			// cout << ' ' << x << ' ' << v << endl;
    			if(dis[v] > dis[x] + val[p])
    			{
    				dis[v] = dis[x] + val[p];
    				q.push((point){v, dis[v]});
    			}
    		}
    	}
    	printf("%lld
    ", dis[t]);
    }
    
    int main()
    {
    	scanf("%d", &n);
    	t = n * n + 1;
    	for(int i = 1; i <= n + 1; i++)	
    		for(int j = 1; j <= n; j++)
    		{
    			int x;
    			scanf("%d", &x);
    			int k = (i - 1) * n + j;
    			// cout << s << ' ' << k << ' ' << t << endl;
    			if(i == 1) add(k, t, x);
    			else if(i == n + 1) k -= n, add(s, k, x);
    			else add(k, k - n, x);
    		}
    	for(int i = 1; i <= n; i++)
    		for(int j = 1; j <= n + 1; j++)
    		{
    			int x;
    			scanf("%d", &x);
    			int k = (i - 1) * n + j;
    			if(j == 1) add(s, k, x);
    			else if(j == n + 1) k--, add(k, t, x);
    			else add(k - 1, k, x);
    		}
    	for(int i = 1; i <= n + 1; i++)	
    		for(int j = 1; j <= n; j++)
    		{
    			int x;
    			scanf("%d", &x);
    			int k = (i - 1) * n + j;
    			if(i == 1) add(t, k, x);
    			else if(i == n + 1) k -= n, add(k, s, x);
    			else add(k - n, k, x);
    		}
    	for(int i = 1; i <= n; i++)
    		for(int j = 1; j <= n + 1; j++)
    		{
    			int x;
    			scanf("%d", &x);
    			int k = (i - 1) * n + j;
    			if(j == 1) add(k, s, x);
    			else if(j == n + 1) k--, add(t, k, x);
    			else add(k, k - 1, x);
    		}
    	// for(int i = s; i <= t; i++)
    	// {
    	// 	cout << i << ' ';
    	// 	for(int p = head[i]; p; p = nxt[p])
    	// 		cout << to[p] << ' ' << val[p] << ' ';
    	// 	cout << endl;
    	// }
    	dij();
    	return 0;
    }
    
  • 相关阅读:
    C++笔记(1)----此运算符函数的参数太多
    算法学习(6)----整数转换为格雷码
    算法学习(5)----二叉树前序、中序、后序遍历互相转换
    算法学习(4)----汉诺塔递归算法和非递归算法
    算法学习(3)----求数组中大小最接近的两个元素的差
    算法学习(2)----丢番图方程
    9.11 Django视图 view和路由
    9.11 Django关于母版语言的灵活用法
    9.10Django模板
    9.9Dajngo MTV
  • 原文地址:https://www.cnblogs.com/LJB00131/p/13229368.html
Copyright © 2020-2023  润新知