【NOIP2018模拟赛2018.10.24 B组】

此题直接暴力枚举 1~1e6 + 1000 左右预处理一个好数数组,然后二分找到询问n位置,往后找m个就行了。。

被行末空格恶心到,,代码变丑了好多。。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pt putchar
#define ex pt('\n')
#define ko pt(' ')
const int MAXN = 1e6 + 5;
const int INF = 1e6 + 1000;
int T,good[MAXN];
int cnt = 0;
void in(int &x)
{
	int num = 0,f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9')
		{num = (num << 3) + (num << 1) + (ch - '0'); ch = getchar();}
	x = num*f;
}
void out(int x)
{
	if(x < 0) x = -x,pt('-');
	if(x > 9) out(x/10);
	pt(x % 10 + '0');
}

bool calc(int x)
{
	int one = 0,two = 0;
	while(x)
	{
		int tmp =  x % 3;
		if(tmp == 1) one++;
		else if(tmp == 2) two++;
		x /= 3;
	}
	return (one == two);
}

void init()
{
	for(int i = 1;i <= INF;i++)
		if(calc(i)) good[++cnt] = i;
}

int main()
{
	init();
	in(T);
	while(T--)
	{
		int n,m;
		in(n); in(m);
		int pos = lower_bound(good+1,good+1+cnt,n) - good;
		for(int i = pos;i < pos+m;i++) 
		{
			out(good[i]);if(i != pos+m-1) ko;
		}
		if(T != 0) ex;
	}
	return 0;
}

此题开始lz写了个set<string>判重,答案就是set长度,70分,后面字符长了MLE了

正解就是用哈希判重。

但是这道题用一个哈希很可能(反正lz没成功)发生冲突,于是我们可以用黑科技"双重哈希“”

就是同时使用两套哈希系统,分别用不同的进制和取模数,只有两套哈希对应的一个字符串的哈希值都一样时我们才认同字符串重复。

还是可以用set,但是这次存的是pair<haxi1,haxi2>,这样就不会爆空间了,答案为set长度。

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pt putchar
#define ex pt('\n')
#define ko pt(' ')
const int MAXN = 2e5 + 5;
const int MOD1 = 1e9 + 7,MOD2 = 233333333;
const int INF = 1e9;
int n,m;
//string s;
char s[MAXN];
ll f1[MAXN],f2[MAXN],c[MAXN],s1,s2;
set<pair<ll,ll> > so;
int e1 = 31,e2 = 131;
void in(int &x)
{
	int num = 0,f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9')
		{num = (num << 3) + (num << 1) + (ch - '0'); ch = getchar();}
	x = num*f;
}
void out(int x)
{
	if(x < 0) x = -x,pt('-');
	if(x > 9) out(x/10);
	pt(x % 10 + '0');
}
int main()
{
	in(n); in(m); 
	f1[0] = f2[0] = 1;
	scanf("%s",s+1);
	for(int i = 1;i <= n;i++) c[i] = s[i] - 'a';
	for(int i = 1;i <= m;i++)	
		f1[i] = f1[i-1]*e1 % MOD1,
		f2[i] = f2[i-1]*e2 % MOD2;
	s1 = s2 = 0;
	for(int i = 1;i <= m;i++)
	{
		s1 = (c[i] + s1*e1 % MOD1) % MOD1;
		s2 = (c[i] + s2*e2 % MOD2) % MOD2;
	}
	so.insert(make_pair(s1,s2));
	for(int i = m+1;i <= n;i++)
	{
		s1 = (s1 - f1[m-1]*c[i-m] % MOD1 + MOD1) % MOD1;
		s2 = (s2 - f2[m-1]*c[i-m] % MOD2 + MOD2) % MOD2;
		s1 = (s1 * e1 + c[i]) % MOD1;
		s2 = (s2 * e2 + c[i]) % MOD2;
		so.insert(make_pair(s1,s2));
	}
	out(so.size());
	return 0;
}

对于此题,我们选择从方差的表达式入手。

已知k是经过的点的数目,而到达终点经过了 k =  (n+m-1)个点。

令N=(n+m-1),此时x(即海拔)的平均值为(x1+x2+x3+…+xN)/N,(为了方便,用x_来代替x的平均值)。

σ^2=((x1-x_)^2+(x2-x_)^2+…+(xN-x_)^2)/N, 

N^2*σ^2 
=N*((x1-x_)^2+…+(xN-x_)^2) 
=N*((x1^2-2*x1*x_)^2+…+(xN^2-2*xN*x_+x_^2)) 
=N*((x1^2+…+xN^2)-2*x_*(x1+…+xN)+N*(x_^2)) 
然后再将x_=(x1+…+xN)/N带入,即可得到ans表达式。 
带入得到答案 ans = N*(x1^2+…+xN^2)-(x1+…+xN)^2。 

那么设计dp :f[i][j][sum] 代表当前坐标在 i,j ,走的总路程为sum时的 x1^2+x2^2+……xn^2 的最小值

最后答案即为max(f[n][m][i]*N - i * i) (0 <= i <= (n+m)*max{h})

代码如下:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pt putchar
#define ex pt('\n')
#define ko pt(' ')
const int MAXN = 50 + 5;
const int INF = 1e9;
int n,m,k;
int ans = INF;
int h[MAXN][MAXN],pre[MAXN][MAXN],len,maxh = 0;
int f[MAXN][MAXN][5005];
void in(int &x)
{
	int num = 0,f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9')
		{num = (num << 3) + (num << 1) + (ch - '0'); ch = getchar();}
	x = num*f;
}
void out(int x)
{
	if(x < 0) x = -x,pt('-');
	if(x > 9) out(x/10);
	pt(x % 10 + '0');
}
 
int times(int x) {return x*x;}
int main()
{
	in(n); in(m); k = n + m - 1;
	for(int i = 1;i <= n;i++)
		for(int j = 1;j <= m;j++)
		{
			in(h[i][j]),maxh = max(maxh,h[i][j]);
			pre[i][j] = times(h[i][j]);
		}
	memset(f,60,sizeof f);
	f[1][1][h[1][1]] = pre[1][1];
	int limit = maxh*k;
	for(int i = 1;i <= n;i++)
		for(int j = 1;j <= m;j++)
			for(int sum = 0;sum <= limit;sum++)
			{
				if(i < n && sum + h[i+1][j] <= limit) 
					f[i+1][j][sum+h[i+1][j]] = min(f[i+1][j][sum+h[i+1][j]],f[i][j][sum] + pre[i+1][j]);
				if(j < m && sum + h[i][j+1] <= limit) 
					f[i][j+1][sum+h[i][j+1]] = min(f[i][j+1][sum+h[i][j+1]],f[i][j][sum] + pre[i][j+1]);
			}
	for(int i = 0;i <= limit;i++)
		if(f[n][m][i] < INF) ans = min(ans,k*f[n][m][i] - i*i);
	out(ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/chang_yl/article/details/83352127