1. 程式人生 > >2018 icpc徐州網路賽

2018 icpc徐州網路賽

F I簽到題,直接模擬即可。

A:

當第一個有2^k種選擇時,由於每一個數相對於的進行XNOR為0的數是一定的,所以第二個數有2^k-1種選擇,因而對於第n個人有2^k-2種選擇,然而,若第n-1個人與第一個人選擇相同時,將第一個數與最後一個數看做同一個數,那麼序列就縮短為n-2的長度,因而如此遞推下去即可求出答案。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define ll long long
#define MOD 1000000007
#define N 1000005
ll a[N];
ll quickpow(ll a, ll b)
{
	ll ans = 1;
	while(b)
	{
		if(b%2)
			ans = ans*a%MOD;
		a = a*a%MOD;
		b /= 2;
	}
	return ans;
}
ll solve(int n, int k)
{
	if(n == 1)
	    return a[k];
	else if(n == 2)
	    return a[k] * (a[k] - 1) % MOD;
	else
	{
		return (a[k] * quickpow(a[k]-1, n-2) % MOD * max(a[k]-2, 0ll) % MOD + solve(n-2, k) % MOD) % MOD;
	}
}
int main()
{
	a[0] = 1;
	for(int i = 1; i < N; i++)
	    a[i] = a[i-1] * 2 % MOD;
	int t;
	scanf("%d", &t);
	while(t--)
	{
		int n, k;
		scanf("%d%d", &n, &k);
		printf("%lld\n", solve(n, k));
	}
	return 0;
}
/*
2
3 1
4 2
*/

H:

1.線段樹做法:

設定兩個陣列,一個sum用來存區間和,另一個sum1用來存(n-l+1)*a[l],這樣每次查詢只需要用在 b到c的區間內的 sum1的區間和減去sum的區間和*(n-c)。(瘋狂TLE的一道線段樹裸題)

#include <cstdio>
#include <cstring>
using namespace std;
#define N 100100
long long sum[N<<2], sum1[N<<2], a[N];
int n;
void Build(int i, int l, int r)
{
	if(l == r)
	{
		sum[i] = a[l];
		sum1[i] = (n - l + 1) * a[l]; 
		return;
	}
	int mid = (l + r) >> 1;
	Build(i<<1, l, mid);
	Build(i<<1|1, mid+1, r);
	sum[i] = sum[i<<1] + sum[i<<1|1];
	sum1[i] = sum1[i<<1] + sum1[i<<1|1];
}
long long Query(int i, int l, int r, int L, int R, long long s[])
{
	if(l <= L && r >= R)
	{
		return s[i];
	}
	int mid = (L + R) >> 1;
	if(r <= mid) return Query(i<<1, l, r, L, mid, s);
	else if(l > mid) return Query(i<<1|1, l, r, mid+1, R, s);
	else return Query(i<<1, l, r, L, mid, s) + Query(i<<1|1, l, r, mid+1, R, s);
}
void Change(int t, int L, int R, long long c, int i)
{
	if(t == L && t == R)
	{
		sum[i] = c;
		sum1[i] = c * (n - t + 1);
		return;
	}
	int mid = (L + R) >> 1;
	if(t <= mid) Change(t, L, mid, c, i<<1);
	else Change(t, mid+1, R, c, i<<1|1);
	sum[i] = sum[i<<1] + sum[i<<1|1];
	sum1[i] = sum1[i<<1] + sum1[i<<1|1];
}
int main()
{
	int q;
	scanf("%d%d", &n, &q);
	for(int i = 1; i <= n; i++)
	    scanf("%lld", &a[i]);
	Build(1, 1, n);
	while(q--)
	{
		long long a, b, c;
		scanf("%lld%lld%lld", &a, &b, &c);
		if(a == 1)
		{
			long long ans = 0;
			ans += Query(1, b, c, 1, n, sum1);
			ans -= (n - c) * Query(1, b, c, 1, n, sum);
			printf("%lld\n", ans);
		}
		else
		{
			Change(b, 1, n, c, 1);
		}
	}
	return 0;
}

2.樹狀陣列做法:

用樹狀陣列字首和求:\sum_{i=l}^{r} \left ( r+1 \right )*a[i] - \sum_{i=l}^{r} i*a[i]

#include <cstdio>
#include <cstring>
using namespace std;
#define N 100005
long long a[N], b[N];
int n, q;
int lowbit(int x)
{
	return x & (-x);
}
long long Query(long long s[], int x)
{
	long long ans = 0;
	for(int i = x; i > 0; i -= lowbit(i))
	{
		ans += s[i];
	}
	return ans;
}
void Change(long long s[], int x, long long c)
{
	for(int i = x; i <= n; i += lowbit(i))
	{
		s[i] += c;
	}
}
int main()
{
	scanf("%d%d", &n, &q);
	for(int i = 1; i <= n; i++)
	{
		long long t;
		scanf("%lld", &t);
		Change(a, i, t);
		Change(b, i, i*t);
	}
	while(q--)
	{
		long long s, l, r;
		scanf("%lld%lld%lld", &s, &l, &r);
		if(s == 1)
		{
			long long ans = (r + 1) * (Query(a, r) - Query(a, l-1)) - (Query(b, r) - Query(b, l-1));
			printf("%lld\n", ans);
		}
		else
		{
			long long x = Query(a, l) - Query(a, l-1);
			Change(a, l, r-x);
			Change(b, l, l*r-l*x);
		}
	}
	return 0;
}

G:手動模擬一遍,然後從後往前計算波浪的長度,模擬的時候就知道怎麼計算長度了...但是一開始用的是陣列加sort然後瘋狂TLE,然後查了之後才知道...用了這麼久的set居然不知道set會自動排序!!!

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
using namespace std;
#define N 50005
int n;
long long X[N], Y[N];
long long solve(long long a[])
{
	set <int> Q;
	set <int> :: iterator it;  //這個時候真的想說set真的很有用...
	long long ans = 0;
	for(int i = n - 1; i >= 0; i--)
	{
		it = Q.lower_bound(a[i]);
		if(it == Q.begin()) ans += a[i];
		else
		{
			it--;
			ans += a[i] - *it;
		}
		Q.insert(a[i]);
	}
	return ans;
}
int main()
{
	scanf("%d", &n);
	for(int i = 0; i < n; i++)
	{
		scanf("%lld%lld", &X[i], &Y[i]);
	}
	printf("%lld\n", solve(X) + solve(Y));
	return 0;
}

J:

求一個最大生成樹+LCA離線演算法