黑龙江重现赛

A水题。
————————————————————————————————————————————
B题水题,这里其实就是,把所有的情况展开,就可以发现公式为(n-1)(an2+an-12…+a12)+(交叉项的所有和)。就是维护交叉项。交叉项可以拿前缀和来维护。
sum
(sum-a[i])就是a[i]与其他所有的乘积,再sum-=a[i]就可以不断循环下去,o(n)就解决了。
水题。


C题,,一秒就能过。。


D题,感觉稍微难一点,不过也就是以为差分数组就能过了。
维护每个区间有多个点重合了。最后统计最大值。

#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
	char ch = getchar(); int x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
int n;
struct node{ int s, e; }sch[100005];
int chaf[100005];
int sum[100005];
int main()
{
	cin >> n;
	int maxx = 0;
	up(i, 0, n)
	{
		scanf("%d%d", &sch[i].s, &sch[i].e);
		maxx = max(maxx, sch[i].e);
	}
	up(i, 0, n)
	{
		chaf[sch[i].s]++;
		chaf[sch[i].e]--;
	}//差分数组,注意e--,因为结束时间是可以成为开始时间的
	int ans = 1;
	upd(i, 0, maxx)
	{
		if(i>0)
			sum[i] = sum[i - 1] + chaf[i];
		else sum[i] = chaf[i];
	}//差分数组扫一遍,得到每个点的值,即每个时间有多少个重合了
	upd(i, 0, maxx)
	{
		ans = max(ans, sum[i]);
	}
	cout << ans << endl;
	return 0;

}


E题没有做,知道是马拉车算法。待补。
已补,裸模板,稍微加点变化。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
	char ch = getchar(); int x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
char model[10010];
char s[5005];
int lens[10010];
int cnt, len;
void  init(int len)
{
	model[cnt++] = '%';
	up(i, 0, len)
	{
		model[cnt++] = '#';
		model[cnt++] = s[i];
	}
	model[cnt++] = '#';
}
int manecher()
{
	lens[0] = 0;
	int sum = 0;
	int mx = 0;
	int st = 0;
	up(i, 1, len)
	{
		if ((i & 1 )== 0)continue;
		if (i < mx)lens[i] = min(lens[2 * st - i], mx - i);
		else lens[i] = 1;
		while (fabs(model[i - lens[i]] - model[i + lens[i]]) == 'a' - 'A'||model[i-lens[i]]=='#')lens[i]++;
		if (lens[i] + i > mx)
		{
			mx = lens[i] + i;
			st = i;
			sum = max(sum, lens[i]);
		}

	}
	return sum - 1;
}
int main()
{
	cin >> s;
	init(strlen(s));
	len = cnt;
	cout << manecher()<<endl;
	return 0;
}

F题,线段树,待补

已补
早知道当时比赛的时候做这道题了,线段树上乱搞就能过了

#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
	char ch = getchar(); int x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
int n, q;
const int N = 2e5 + 5;
ll tree[4 * N];
bool one[4 * N];
ll gcd(ll a, ll b)
{
	return b == 0 ? a : gcd(b, a%b);
}
void pushup(int root) {
	tree[root] = gcd(tree[root << 1], tree[root << 1 | 1]);
	one[root] = one[root << 1] && one[root << 1 | 1];
}
void build(int l,int r,int root){
	int mid = (l + r) >> 1;
	if (l == r)
	{
		scanf("%lld", &tree[root]);
		one[root] = tree[root] == 1;
		return;
	}
	build(l, mid, root << 1);
	build(mid + 1, r, root << 1 | 1);
	pushup(root);
}
void  update(int l, int r, int a,int b,int root)
{
	if (one[root])//剪枝,不然时间爆炸了
	{
		return;
	}
	if (l == r)
	{
		tree[root] =(ll) sqrt(tree[root]);
		if (tree[root] == 1)one[root] = 1;
		return;
	}
	int mid = (l + r) >> 1;
	if (a <= mid)update(l, mid, a, b, root << 1);
	if (b > mid)update(mid + 1, r, a, b, root << 1 | 1);
	pushup(root);
}
ll querry(int l, int r, int a, int b, int root)
{
	if (one[root])return (ll)1;
	int mid = (l + r) >> 1;
	if (l >= a && r <= b)return tree[root];
	ll g = 0;
	if (mid < b)g = gcd(g, querry(mid + 1, r, a, b, root << 1 | 1));
	if (a <= mid)g = gcd(g, querry(l, mid, a, b, root << 1));
	return g;
}
int main()
{
	cin >> n;
	build(1, n, 1);
	cin >> q;
	int t;
	int x, y;
	while (q--)
	{
		scanf("%d", &t);
		if (t == 0)
		{
			scanf("%d%d", &x, &y);
			update(1, n, x, y,1);
		}
		else
		{
			scanf("%d%d", &x, &y);
			cout << querry(1, n, x, y, 1)<<endl;
		}
	}
	return 0;

}

G题水题,简单博弈论。
巴士博弈模板。
只不过要把0改成1,最后留下一个肯定必败

#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);	
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
	char ch = getchar(); int x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
int t;
int p, m;
int main()
{
	cin >> t;
	while (t--)
	{
		cin >> p >> m;
		if (p % (m + 1) == 1)cout << "Bob" << endl;
		else cout << "Alice" << endl;
	}
	return 0;
}


H题,,和B题难度55开吧。


J题,简单dp
大概就是从1开始往后不断扫一遍,不断去遍历自己的倍数的点,类似于埃氏筛选的感觉,因为当前点肯定是已经最优值,可以用它来不断松弛后面的点。虽然是双线边,不过思考一下就知道走回头路肯定比直接到慢得多。

#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
	char ch = getchar(); int x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
const int N = 5e5 + 10;
//bool used[N];
ll dp[N];
int n;
void init(int n)
{
	dp[1] = 0;
	upd(i, 1, n)
	{
		for (int j = 2*i; j <= n; j += i)
		{
			dp[i] = min(dp[i], dp[j] + (ll)(j - i)*(j - i));//这里是当时脑残了,不过不影响
			dp[j] = min(dp[j], dp[i] + (ll)(j - i)*(j - i));
		}
	}
}
int main()
{
	cin >> n;
	fill(dp, dp + N, 1e15);
	init(n);
	upd(i, 1, n)
		printf("%lld ", dp[i]);
	return 0;
}

J题
定义dist为|i2-j2|+|ai2-aj2|,现在求给出的所有pair中,dist最大的那个。
第一时间上了差分数组。。。然后维护连续区间的和就能够表示ai2-aj2,但是大小关系不确定,而且会有i,j的影响如果i,j大了的话。
说实话被排行榜影响了,觉得很难。。
然后仔细思考发现其实分开两种情况讨论就行了。
假设i<j,就有,dist=|ai2-aj2|+j2+i2
拆开就是两种情况。
然后分别维护,xx+ii的情况和ii-xx。
然后两种情况的最大最小值之差取大的那个就好了。可以证明这样是对的。

#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
	char ch = getchar(); int x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
int n;
int t;
ll x;
int main()
{
	cin >> t;
	while (t--)
	{
		cin >> n;	
		ll minnadd = 9e18;
		ll maxmis=-9e18;
		ll maxadd=-9e18;
		ll minnmis = 9e18;
		upd(i, 1, n)
		{
			scanf("%lld", &x);
			minnadd = min(ll((ll)i*i + x * x), minnadd);
			maxadd = max(ll((ll)i*i + x * x), maxadd);
			minnmis = min(minnmis, ll((ll)i*i - x * x));
			maxmis = max(maxmis, ll((ll)i*i - x * x));
		}
		cout << max(maxadd - minnadd, maxmis - minnmis)<<endl;
	}
	return 0;
}

K题,贪心算法。被卡了好久。。一直在模拟,结果,一直错。。
问的是,将n分成两个数字a,b,求a,b的各位之和的最大值。我们可以知道的
假如给一个数字,把他分成每一位来看,他必然可以看成是,除了第一位以外,其他为看成是
10+n(1<=n<=8) 因为不可能有两个数字相加等于19。
所以我们贪心先,贪一个(n-1)个9组成的数组,例如给的5002,贪心999。
那么这样做就可以转化成我们上面说的那种方法,5002-999,让除了第一位的每一位,变成了10+当前为,如果当前位置是9,那么0就是这个位置上最大的。
因为每一个数位上相加可以是10-18,所以我们贪心最大肯定是向前借一位,当前为+10,这样前一位才-1,整体加9,所以这样做肯定是最大。

#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
	char ch = getchar(); int x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
int t;
ll n;
ll sum = 0;
ll update(int len)
{
	ll k = 0;
	up(i, 0, len)
	{
		k = k * 10 + 9;
		sum += 9;
	}
	return k;
}
int main()
{
	cin >> t;
	while (t--)
	{	
		sum = 0;
		cin >> n;
		ll n1 = n;
		int len = 0;
		while (n)
		{
			n /= 10;
			len++;
		}
		ll temp=update(len - 1);
		n1 -= temp;
		while (n1)
		{
			sum += n1 % 10;
			n1 /= 10;
		}
		cout << sum << endl;
		
	}
	return 0;
}

可惜没有全部写完啊五个小时,可惜了,自己还有很多不足,特别是数论。今后还是多研究下数论吧哎。

猜你喜欢

转载自blog.csdn.net/weixin_44019404/article/details/89576368