8.31总结

        昨晚打cf太晚了,今天早上又去做了核酸,写完8.30号的时候,已经11点多了。然后,早上没学习,下午又玩到了3点,才开始学习。学了一会,去地里看了看杂草,然后写题写到八点多,就在打王者。然后又做饭,啧,今天感觉根本就没怎么学习。

[SDOI2016]排列计数 - 洛谷

错排:a[i]==i的情况有Cnm,我们只需要考虑不同的情况。不同的话,显然,d[1]=0;d[2]=1;对于1,2来说,如果1选2,2选1,则情况有d[i-2]种,如果1选2,2不能选1的话,这样就和1不能选1,相同了。因此,剩下的d[i]=(i-1) *(d[i-1]+d[i-2])种, 则最终结果为 Cnm*(d[n-m])

注意:当n==m 结果为1,当 n-m==1,结果为0,当m==0,结果为d[n],其余的可以根据上述表达式解决。明天需要总结组合数,那几个算法。

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define inf 1e9
#define x first
#define y second

typedef long long ll;
typedef pair<int, int>pii;

const int N = 1e6 + 10;
const int mod = 1e9 + 7;


int qumi(int a, int k, int p)
{
	int res = 1;
	while (k)
	{
		if (k & 1) res = res * a % p;
		a = a * a % p;
		k >>= 1;
	}
	return res;
}

int d[N];
int f[N];
int inv[N];

void init()
{
	d[1] = 0; d[2] = 1; 
	for (int i = 3; i <= N; i++)
		d[i] = (i - 1) * (d[i - 1] + d[i - 2]) % mod;


	f[0] = 1; inv[0] = 1;
	for(int i=1;i<=N;i++)
	{
		f[i] = f[i-1] * i % mod;
		inv[i] = inv[i-1] * qumi(i, mod -2, mod) % mod;
	}

}


signed main()
{
	ios::sync_with_stdio(false); cin.tie(0); cin.tie(0);

	init();
	int t = 1;
	cin >> t;
	while (t--)
	{
		int n, m;
		cin >> n >> m;
		if(m == n) cout << 1 << endl;
		else if(n - m == 1) cout << 0 << endl;
		else if(m == 0) cout << d[n] << endl;
		else
		{
			int res = f[n] * inv[n - m] % mod * inv[m] % mod;
			cout << res * d[n - m] % mod << endl; 
		}
			
	}


	return 0;
}

Problem - E - Codeforces

题意:给你n个矩形,长宽分别为li,wi,q次询问,问有多少个矩形在第一个矩形和第二个矩形之中,求出面积。

解析:我们可以把矩形的宽度和长度,当x值,y值,这样就转换为一个二维前缀和的问题。因为必须严格大于,或者是严格小于,因此,需要++,或者是--。

vector,二维数组的创建方式,也需要学习一下。


void solve()
{
	vector s(1010, vector<int>(1010));
	int n, m; cin >> n >> m;
	for (int i = 1; i <= n; i++)
	{
		int x, y;
		cin >> x >> y;
		s[x][y] += x * y;
	}
 
	for (int i = 1; i <= 1000; i++)
	{
		for (int j = 1; j <= 1000; j++)
		{
			s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];
			// cout << s[i][j] << endl;
		}
		// cout << i ;
	}
	// cout << 111 << endl;
	while (m--)
	{
		int x1, y1, x2, y2;
		cin >> x1 >> y1 >> x2 >> y2;
 
		x1++, y1++;
		x2--, y2--;
 
		cout << s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1] << endl;
 
	}
 
 
}

Problem - F - Codeforces

题意:询问有多少个L,’L‘可以进行反转,且互相之间不能相连。

解析:采用bfs,枚举八个方向,找连通块中*的个数,其必须为3。 但是还可能出现***,或者是纵向的,或者是斜着。因此,我们需要判断这三个*的相对位置。

int dis(pii a, pii b)
{
	return abs(a.first - b.first) + abs(a.second - b.second);
}
 
bool bfs(int tx, int ty)
{
	queue<pii> q;
	q.push({tx, ty});
	st[tx][ty] = true;
 
	int dx[] = {-1, 1, 0, 0, -1, -1, 1, 1};
	int dy[] = {0, 0, 1, -1, -1, 1, -1, 1};
 
	int num = 1;
 
	vector<pii> v;
 
	while (!q.empty())
	{
		auto t = q.front();
		q.pop();
 
		for (int i = 0; i < 8; i++)
		{
			int x = t.first + dx[i];
			int y = t.second + dy[i];
 
			if (x < 1 || x > n || y < 1 || y > m)
				continue;
			if (st[x][y] || a[x][y] == '.')
				continue;
 
			num++;
			q.push({x, y});
			st[x][y] = true;
 
			v.push_back({x, y});
		}
	}
	// cout << num << endl;
	bool ok = true;
	if (v.size() != 2)
		return false;
 
	pii t = {tx, ty};
 
	if ((dis(v[0], t) == 1 && dis(v[1], t) == 1))
		ok = true;
	else if ((dis(v[0], t) == 1 && dis(v[1], t) == 2 && dis(v[0], v[1]) == 1))
		ok = true;
	else if (dis(v[1], t) == 1 && dis(v[0], t) == 2 && dis(v[0], v[1]) == 1)
		ok = true;
	else
		ok = false;
 
	if (v[0].first == v[1].first && v[1].first == tx)
		ok = false;
	if (v[0].second == v[1].second && v[1].second == ty)
		ok = false;
 
	// cout << ok <<"  "<< num << endl;
	if (num != 3 || !ok)
		return false;
	else
		return true;
}
 
void solve()
{
	memset(st, false, sizeof st);
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			cin >> a[i][j];
 
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
		{
			if (a[i][j] == '*' && !st[i][j])
			{
				if (bfs(i, j) == false)
				{
					cout << "NO" << endl;
					return;
				}
			}
		}
	}
	cout << "YES" << endl;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值