Educational Codeforces Round 5 A---E

总结:

场上VP的时候一定要想清楚,再敲代码!!!
debug很搞心态的。
实际上这场整体来说较为简单。C题BFS,D题双指针,E题整除分块。

A. Comparing Two Long Integers

		string a, b;
		cin >> a >> b;
		string aa, bb;
		int len = a.length();
		bool f = false;
		for(int i = 0 ; i < len ; i ++)
		{
			if(f)
			aa += a[i];
			if(a[i] != '0' && !f)
			f = true, aa += a[i];
		}
		len = b.length();
		f = false;
		for(int i = 0; i < len ; i ++)
		{
			if(f)
			bb += b[i]; 
			if(b[i] != '0' && !f)
			f = true, bb += b[i];
			
		}
		int len1 = aa.length();
		int len2 = bb.length();
		if(len1 == len2)
		{
			int flog = 0;
			for(int i = 0 ; i < len1 ; i ++)
			{
				if(aa[i] > bb[i])
				{
					flog = 1;
					break;
				}
				else if(aa[i] < bb[i])
				{
					flog = -1;
					break;	
				}
			}
			if(flog == 1) printf(">\n");
			else if(flog == -1) printf("<\n");
			else printf("=\n");
		}
		else if(len1 > len2)
		{
			printf(">\n");
		}
		else
		{
			printf("<\n");
		}

B. Dinner with Emma

int main()
{
	int n, m;
	scanf("%d %d", &n, &m);
	for(int i = 1 ; i <= n ; i ++)
	h[i] = INF;
	for(int i = 1 ; i <= n ; i ++)
	{
		for(int j = 1 ; j <= m ; j ++)
		scanf("%d", &mm[i][j]), h[i] = min(h[i], mm[i][j]); 
	}
	sort(h + 1, h + n + 1);
	printf("%d\n", h[n]);
	return 0;
}

C. The Labyrinth

题意:

给定n * m的矩阵,求每个*点能遇到多少白点。

思路:

非常明显可以预处理所有白点所在的连通块。然后对于每个*点,只要四个方向上遇到白点且互不在同一个连通块就可作为贡献。(不在同一连通块可对每个连通块进行标号)
在bfs搜四个方向的其他点时,要先检查坐标是否合法,因为 && 操纵从左到右进行的,一直到第一个不满足的时候才会结束,如果先判断是否为.那么坐标可能会出现负值,导致re。

code:

int dx[] = {-1, 0, 1, 0};
int dy[] = {0, 1, 0, -1};
int c[1010][1010];
int id[1010 * 1010];
void bfs(int x, int y, int cnt)
{
	book[x][y] = true;
	queue <note> alls;
	alls.push({x, y, 1});
	vector <PII> ALLS;
	ALLS.push_back({x, y});
	int ans = 1;
	while(!alls.empty())
	{
		auto t = alls.front();
		alls.pop();
		for(int i = 0 ; i < 4 ; i ++)
		{
			int temp_x = t.x + dx[i];
			int temp_y = t.y + dy[i];
			if(temp_x >= 0 && temp_x < n && temp_y >= 0 && temp_y < m && !book[temp_x][temp_y] && mm[temp_x][temp_y] == '.' )
			{
				book[temp_x][temp_y] = true;
				alls.push({temp_x, temp_y, t.w + 1});
				ans ++;
				ALLS.push_back({temp_x, temp_y});	
			}			
		}
	}
	for(auto t : ALLS)
	c[t.first][t.second] = cnt;
	id[cnt] = ans;
}
int main()
{
	scanf("%d %d", &n, &m);
	for(int i = 0 ; i < n ; i ++)
	{
		scanf("%s", mm[i]);
	}
	int cnt = 0;
	for(int i = 0 ; i < n ; i ++)
	{
		for(int j = 0 ; j < m ; j ++)
		{
			if(mm[i][j] == '.' && !book[i][j])
			{
				bfs(i, j, ++ cnt);
			}
		}
	}
	for(int i = 0 ; i < n ; i ++)
	{
		for(int j = 0 ; j < m ; j ++)
		{
			if(mm[i][j] == '*')
			{
				c[i][j] = 1;
				set <int> st;
				for(int k = 0 ; k < 4 ; k ++)
				{
					int temp_x = i + dx[k];
					int temp_y = j + dy[k];
					if(temp_x >= 0 && temp_x < n && temp_y >= 0 && temp_y < m && mm[temp_x][temp_y] == '.') 
					{
						st.insert(c[temp_x][temp_y]);
					}	
				}
				for(auto t : st)
				c[i][j] += id[t];
			}
		}
	}
	for(int i = 0 ; i < n ; i ++)
	{
		for(int j = 0 ; j < m ; j ++)
		{
			if(mm[i][j] == '.')
			cout << mm[i][j];
			else printf("%d", c[i][j] % 10);
		}
		printf("\n");
	}
	return 0;
}

D. Longest k-Good Segment

题意:

找最长的一段区间包含<=k个不同的权值。

思路

明显的双指针。满足xx条件的最长区间问题

code:

int a[maxn], book[maxn];
int main()
{
	int n, k;
	scanf("%d %d", &n, &k);
	for(int i = 1 ; i <= n ; i ++)
	{
		scanf("%d", &a[i]);
	}
	int res = 0, l = 0, r = 0;
	for(int i = 1 , j = 1 , cnt = 0 ; i <= n ; i ++)
	{
		while(j <= n)
		{
			book[a[j]] ++;
			if(book[a[j]] == 1)
			{
				if(cnt + 1 <= k)
				{
					cnt += 1, j ++;
				}
				else
				{
					book[a[j]] --;
					break;
				}
			}
			else j ++;
		}
		if(j - 1 - i + 1 > res)
		res = j - 1 - i + 1, l = i, r = j - 1;
		book[a[i]] --;
		if(book[a[i]] == 0) cnt --;
	}
	printf("%d %d\n", l, r);
	return 0;
}

E. Sum of Remainders

题意:

∑ i = 1 m n    m o d    i \sum_{i = 1} ^ {m} n\; mod\; i i=1mnmodi,其中n和m <= 1e13

思路:

直接暴力肯定不行。
考虑化简式子
非常经典的转换 n    m o d    i = n − ⌊ n / i ⌋ ∗ i n\; mod \; i = n - \lfloor n / i \rfloor * i nmodi=nn/ii
那么原式变为 ∑ i = 1 m n − ⌊ n / i ⌋ ∗ i \sum_{i = 1} ^ {m} n - \lfloor n / i \rfloor * i i=1mnn/ii
进一步转化 n ∗ m − ∑ i = 1 m ⌊ n / i ⌋ ∗ i n * m - \sum_{i = 1} ^ {m}\lfloor n / i \rfloor * i nmi=1mn/ii
∑ i = 1 m ⌊ n / i ⌋ \sum_{i = 1} ^ {m} \lfloor n / i \rfloor i=1mn/i非常经典的整除分块问题
∑ i = 1 m ⌊ n / i ⌋ ∗ i \sum_{i = 1} ^ {m} \lfloor n / i \rfloor * i i=1mn/ii相当于在[l, r]区间上的一个等差数列求和。

code:

typedef long long ll;
const int INF = 0x3f3f3f3f;
const int maxn = 1e5 + 10;
typedef pair <int, int> PII;
const ll mod = 1e9 + 7;
ll get_mod1(ll a, ll b)
{
	return (a % mod + (b % mod)) % mod;
}
ll get_mod2(ll a, ll b)
{
	return (a % mod * (b % mod)) % mod;
}
ll ksm(ll base, ll power)
{
	ll res = 1;
	while(power)
	{
		if(power & 1)
		res = get_mod2(res, base);
		base = get_mod2(base, base);
		power >>= 1;
	}
	return res;
}
int main()
{
	ll n, m;
	scanf("%lld %lld", &n, &m);
	ll res = get_mod2(n, m);
	ll inv2 = ksm(2ll, mod - 2);
	ll temp = 0;
	for(ll l = 1, r ; l <= min(n, m) ; l = r + 1)
	{
		r = min(m , n / (n / l));
		temp = get_mod1(temp, get_mod2(inv2, get_mod2(r - l + 1, get_mod2(n / l, l + r))));
	}
	printf("%lld\n",(res - temp + mod) % mod);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值