Loading

2021牛客寒假算法基础集训营6 ACDFGIJ

A. 回文括号序列计数

坑比题...注意回文的定义,并不是括号序列对称。比如(())不是回文的而))是回文的。而合法括号列左右两端一定是(和),必然非回文,因此只有空串答案是1.

#include <iostream>
using namespace std;
#define mod 998244353
int n;
int main()
{
	//freopen("data.txt", "r", stdin);
	int t;
	cin >> t;
	while(t--)
	{
		cin >> n;
		if(!n) cout << 1 << endl;
		else cout << 0 << endl;
	}
	return 0;
}

C. 末三位

快速幂会t,因此可以找规律。

证明详见https://blog.nowcoder.net/n/caa12c854288451a9bf1288a291a8e15

#include <iostream>
using namespace std;
int n;
int main()
{
	freopen("data.txt", "r", stdin);
	while(cin >> n)
	{
		if(n == 0) cout << "001" << endl;
		else if(n == 1) cout << "005" << endl;
		else if(n == 2) cout << "025" << endl;
		else if(n == 3) cout << "125" << endl;
		else if(n == 4) cout << "625" << endl;
		else if(n & 1) cout << "125" << endl;
		else cout << "625" << endl;
	}
	return 0;
}

D. 划数

“已知其中一个数cnt(cnt >= 11)”,而两数相加对11取模后肯定小于11,因此这肯定是数列的一个原本的数,那么剩下另一个数就是原来序列其他数的和。根据取模运算律直接计算即可。注意n = 2要特判。

#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
int n, cnt, a[150005], sum = 0;
int main()
{
	freopen("data.txt", "r", stdin);
	while(cin >> n >> cnt)
	{
		sum = 0;
		for(int i = 1; i <= n; i++)
		{
			cin >> a[i];
			sum = (sum + a[i]) % 11;
		}
		if(n == 2)
		{
			if(cnt == a[1]) cout << a[2] << endl;
			else cout << a[1] << endl;
			continue;
		}
		cout << (sum - cnt % 11 + 11) % 11 << endl;//cnt >= 11 肯定是数列的一个数 那么输出的就是剩下部分的和
	}
	return 0;
}

F. 组合数问题

打表找规律可以解决,发现每次都是2的次幂附近的数,这些数与最近的2的次幂作差的绝对值又恰好是等比数列...

证明见官方题解https://ac.nowcoder.com/discuss/599236?type=101&order=0&pos=1&page=1&channel=-1&source_id=1或者大佬博客https://blog.nowcoder.net/n/4682f520b038471dab543ab91c197727。

#include <iostream>
#define p 998244353
#define LL long long
#define maxn 100005
using namespace std;
void extend_gcd(LL a,LL b,LL &x,LL &y){
    if(b==0){
        x=1,y=0;
        return;
    }
    extend_gcd(b,a%b,y,x);
    y-=a/b*x;
}

LL inv[maxn + 10];
LL f[maxn+10];
void init(){//阶乘及其逆元打表
    f[0]=1;
    for(int i=1;i<=maxn;i++){
        f[i]=f[i-1]*i%p;
    }

    LL x,y;
    extend_gcd(f[maxn],p,x,y);//先求出f[N]的逆元,再循环求出f[1~N-1]的逆元
    inv[maxn]=(x%p+p)%p;
    for(int i=maxn-1;i>=1;i--){
        inv[i]=inv[i+1]*(i+1)%p;
    }
}

LL C(LL n,LL m){
    if(n==m||m==0)return 1;
    return (f[n]*inv[m]%p*inv[n-m]%p)%p;
}
long long fpow(long long a, long long b)
{
	long long ans = 1;
	for(; b; b >>= 1)
	{
		if(b & 1) ans = ans * a % p;
		a = a * a % p;
	}
	return ans;
}
int main()
{
	//init();
	// int n = 4;
	// LL ans = 0;
	// for(int i = 0; i <= n; i += 4)
	// {
	// 	ans = (ans + C(n * 1ll, i * 1ll)) % p;
	// }
	// cout << ans;
	freopen("data.txt", "r", stdin);
	long long n;
	cin >> n;
	cout << (fpow(2, n - 2) + p + ((n / 4) & 1 ? -1 : 1) * 2 * fpow(4, n / 4 - 1) % p) % p;
	return 0;
}

G. 机器人

全排列会t(因为没法剪枝),考虑贪心:

两个机器人时:\(a_1(a_2x+b_2)+b_1<a_2(a_1x+b_1)+b_2\),可以推广到多个,因此按照这个策略排序后计算答案即可。

答案会爆long long,因此用__int128存储(or 高精度 or 两个long long)

#include <iostream>
#include <algorithm>
#include <map>
#include <vector>
using namespace std;
int n;
__int128 x;
bool vis[25];
long long ans = 0;
struct robot
{
	long long a, b;
} r[25];
bool cmp(robot x, robot y)
{
	//return (x.a - 1) * 1.0 / x.b < (y.a - 1) * 1.0 / y.b;
	return x.b + x.a * y.b < y.b + y.a * x.b;
}
char ibuf[1000050],*s=ibuf;

inline __int128 read()
{
    __int128 x=0,f=1;
    char ch=getchar();
    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;
}

inline void write(__int128 x)
{
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    if(x>9)
        write(x/10);
    putchar(x%10+'0');
}
int main()
{
	freopen("data.txt", "r", stdin);
	cin >> n;
	x = read();
	for(int i = 1; i <= n; i++)
	{
		cin >> r[i].a >> r[i].b;
	}
	sort(r + 1, r + n + 1, cmp);
	for(int i = 1; i <= n; i++)
	{
		x = x * r[i].a + r[i].b;
	}
	write(x);
	return 0;
}

I. 贪吃蛇

注意到尾巴不缩回,实际上就是BFS.

#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
int n, m;
char mmap[105][105];
bool vis[105][105];
struct node
{
	int x, y, len;
};
node s, t;
int ans = 0x3f3f3f3f;
int dir[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
void bfs()
{
	queue<node> q;
	q.push(s);
	while(q.size())
	{
		node now = q.front();
		q.pop();
		//cout << now.x << ' ' << now.y  << endl;
		if(now.x == t.x && now.y == t.y)
		{
			ans = now.len;
			break;
		}
		for(int i = 0; i < 4; i++)
		{
			int nx = now.x + dir[i][0], ny = now.y + dir[i][1];
			if(!vis[nx][ny] && nx >= 1 && nx <= n && ny >= 1 && ny <= m)
			{
				vis[nx][ny] = 1;
				node nxt;
				nxt.x = nx, nxt.y = ny, nxt.len = now.len + 1;
				q.push(nxt);
			}
		}
	}
}
int main()
{
	//freopen("data.txt", "r", stdin);
	memset(vis, 0, sizeof(vis));
	cin >> n >> m;
	cin >> s.x >> s.y >> t.x >> t.y;
	s.len = 0;
	for(int i = 1; i <= n; i++)
	{
		scanf("%s", mmap[i] + 1);
	}
	for(int i = 1; i <= n; i++)
	{
		for(int j = 1; j <= m; j++)
		{
			if(mmap[i][j] == '#')
			{
				vis[i][j] = 1;
			}
		}
	}
	vis[s.x][s.y] = 1;
	bfs();
	if(ans != 0x3f3f3f3f) cout << ans * 100;
	else cout << -1;
	return 0;
}


J. 天空之城

观察到走过的路代价为0,就是裸的MST。

#include <iostream>
#include <algorithm>
#include <map>
#include <vector>
using namespace std;
#define mod 998244353
int n, q, city = 0;
struct edge
{
	int x, y, z;
};
bool cmp(edge a, edge b)
{
	return a.z < b.z;
}
int fa[5005];
int get(int x)
{
	if(x == fa[x]) return x;
	return fa[x] = get(fa[x]);
}
int main()
{
	//freopen("data.txt", "r", stdin);
	while(cin >> n >> q)
	{
		vector<edge> v;
		for(int i = 1; i <= n; i++) fa[i] = i;
		map<string, int> mp;
		city = 0;
		string tmp;
		cin >> tmp;
		mp[tmp] = ++city;
		int cnt = 0;
		for(int i = 1; i <= q; i++)
		{
			string uu, vv;
			int x, y, w;
			cin >> uu >> vv >> w;
			if(mp.find(uu) != mp.end())
			{
				x = mp[uu];
			}
			else x = mp[uu] = ++city;
			if(mp.find(vv) != mp.end())
			{
				y = mp[vv];
			}
			else y = mp[vv] = ++city;
			edge ee;
			ee.x = x, ee.y = y, ee.z = w;
			v.push_back(ee);
		}
		sort(v.begin(), v.end(), cmp);
		long long ans = 0;
		for(int i = 0; i < v.size(); i++)
		{
			if(cnt == n - 1) break;
			int x = v[i].x, y = v[i].y;
			int xx = get(x), yy = get(y);
			if(xx == yy) continue;
			ans += 1ll * v[i].z;
			fa[xx] = yy;
			cnt++;
		}
		if(cnt == n - 1) cout << ans << endl;
		else cout << "No!" << endl;
	}
}
posted @ 2021-02-24 20:38  脂环  阅读(85)  评论(0编辑  收藏  举报