• 【2021夏纪中游记】2021.7.12模拟赛


    2021.7.12模拟赛

    比赛概括:

    (mathrm{sum}=40+0+0+5)

    唉。

    T1 好元素:

    题目大意:

    找到 (a_1+a_2+a_3=a_4) 的个数((1,2,3) 可以相等)。

    思路:

    一眼题,用将 (a_1+a_2+a_3=a_4) 转移为 (a_1+a_2=a_4-a_3),然后 (mathcal{O}(n^2)) 加哈希。

    但是不能用 map,否则回超时。

    代码:

    const int N = 5e3 + 10;
    
    inline ll Read()
    {
    	ll x = 0, f = 1;
    	char c = getchar();
    	while (c != '-' && (c < '0' || c > '9')) c = getchar();
    	if (c == '-') f = -f, c = getchar();
    	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
    	return x * f;
    }
    
    int n, mod = 25000003, ans;
    ll a[N];
    int hash[25000005];
    
    inline int Hash(int val, int op = 1)
    {
    	int x = (val % mod + mod) % mod;
    	for (; hash[x] != 1010580540 && hash[x] != val; x = (x + 1) % mod);
    	if (op)
    		return x;
    	hash[x] = val;
    	return 0;
    }
    
    int main()
    {
    	freopen("good.in", "r", stdin);
    	freopen("good.out", "w", stdout);
    	memset (hash, 60, sizeof hash);
    	n = Read();
    	for (register int i = 1; i <= n; i++)
    	{
    		a[i] = Read();
    		for (register int j = 1; j < i; j++)
    			if(hash[Hash(a[i] - a[j])] == a[i] - a[j]) {ans++; break;}
    		for (register int j = 1; j <= i; j++)
    			if(hash[Hash(a[i] + a[j])] != a[i] + a[j]) Hash(a[i] + a[j], 0);
    	}
    	printf ("%d
    ", ans);
    	return 0;
    }
    

    T2 最短路径:

    题目大意:

    在平面直角坐标系内的 (n) 个点,选择两条路径使得所有点必须被经过,且 (b1) 必在路线一、(b2) 必在路线二。

    思路:

    由于确定了路线一,路线二就也确定了,所以一开始想到的状态是设 (f_{i,j}) 表示路线一从 (j) 来到 (i) 的最小值,但是这么设会导致路线二很难连接。

    因此,考虑两个路线一起设,设 (f_{i,j}) 表示路线一正着走到 (i)、路线二倒着走到 (j) 的最小数。则有:

    [egin{aligned} f_{i,k}&=min{f_{i,j}+mathrm{dis}(j,k)}\ f_{k,j}&=min{f_{i,j}+mathrm{dis}(i,k)} end{aligned}]

    其中 (k=max(i,j)+1)(n) 时要特判处理。

    代码:

    const int N = 1010;
    
    inline ll Read()
    {
    	ll x = 0, f = 1;
    	char c = getchar();
    	while (c != '-' && (c < '0' || c > '9')) c = getchar();
    	if (c == '-') f = -f, c = getchar();
    	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
    	return x * f;
    }
    
    int n, b1, b2;
    struct point
    {
    	int x, y, id;
    }a[N];
    
    bool cmp (point a, point b)
    {
    	return a.x < b.x;
    }
    
    double f[N][N];
    
    double Dis(int i, int j)
    {
    	return sqrt((a[i].x - a[j].x) * (a[i].x - a[j].x) +
    	 (a[i].y - a[j].y) * (a[i].y - a[j].y));
    }
    
    int main()
    {
    	freopen("path.in", "r", stdin);
    	freopen("path.out", "w", stdout);
    	n = Read(), b1 = Read(), b2 = Read(); b1++, b2 ++;
    	for (int i = 1; i <= n; i++)
    		a[i].x = Read(), a[i].y = Read(), a[i].id = i;
    	sort (a + 1, a + 1 + n, cmp);
    	a[0] = a[1];
    	for (int i = 1; i <= n; i++) 
    	{
    		if (a[i].id == b1) b1 = a[i].id;
    		if (a[i].id == b2) b2 = a[i].id;
    	}
    	for (int i = 1; i <= n; i++)
    		for (int j = 1; j <= n; j++)
    			f[i][j] = 1e9;
    	f[1][1] = 0;
    	for (int i = 1; i <= n; i++)
    		for (int j = 1; j <= n; j++)
    		{
    			int k = max(i, j) + 1;
    			if (max(i, j) == n) 
    			{
    				if (i == n) f[n][n] = min(f[n][n], f[n][j] + Dis(j, n));
    				else f[n][n] = min(f[n][n], f[i][n] + Dis(i, n));
    				continue;
    			}
    			if (k != b1) f[i][k] = min(f[i][k], f[i][j] + Dis(j, k));
    			if (k != b2) f[k][j] = min(f[k][j], f[i][j] + Dis(i, k));
    		}
    	printf ("%.2lf
    ", f[n][n]);
    	return 0;
    }
    

    T3 [GDOI2016]最长公共子串:

    题目大意:

    给两个字符串 (s,t)。可对 (s) 的一些区间进行任意排列,使得 (s,t) 的最长公共子串最大,求其长度。

    正文:

    难确实难。有一个很显然的性质,有交集的区间就让它们并在一起,使范围缩小到 (O(n)) 级。

    然后考虑匹配,由于区间内的可以按任意顺序,我们就把区间看作一个整体,匹配就是和 (t) 比字母数量。设 (f_{i,j}) 表示 (s)(i) 区间、(t)(j) 字符开始的最长长度。那么就照上文说的,比字母数量。

    得到了 (f) 后,就能得到 (g_{i,j}) 表示 (s)(i) 区间开始、(t)(j) 字符开始的最长长度。

    然后随便统计答案。

    总结:本题思路以小见大((f ightarrow g))。

    代码:

    const int N = 2010, M = 1e5 + 10;
    
    inline ll Read()
    {
    	ll x = 0, f = 1;
    	char c = getchar();
    	while (c != '-' && (c < '0' || c > '9')) c = getchar();
    	if (c == '-') f = -f, c = getchar();
    	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
    	return x * f;
    }
    
    char s[N], t[N];
    int n, m, k;
    struct node
    {
    	int l, r;
    	bool operator < (const node &a) const
    	{
    		return l < a.l;
    	}
    }a[M];
    int num[N][27];
    int f[N][N], g[N][N];
    int bucket[27];
    int tot, ans;
    
    int main()
    {
    	freopen("lcs.in", "r", stdin);
    	freopen("lcs.out", "w", stdout);
    	scanf("%s%s", t + 1, s + 1);
    	n = strlen(t + 1), m = strlen(s + 1);
    	k = Read();
    	for (int i = 1; i <= k; i++)
    		a[i].l = Read() + 1, a[i].r = Read() + 1;
    	for (int i = 1; i <= n; i++)
    		a[++k] = (node) {i, i};
    	sort (a + 1, a + 1 + k);
    	tot = 1;
    	for (int i = 2; i <= k; i++)
    	{
    		if (a[i].l <= a[tot].r) a[tot].r = max(a[tot].r, a[i].r);
    		else a[++tot] = a[i];
    	}
    	k = tot;
    	for (int i = 1; i <= k; i++)
    		for (int j = a[i].l; j <= a[i].r; j++)
    			num[i][s[j] - 'a']++;
    	
    	for (int i = k; i; i--)
    		for (int j = m; j; j--)
    		{
    			int len = a[i].r - a[i].l + 1, l = j;
    			for (; l <= min(m, len + j - 1); l++)
    			{
    				if (num[i][t[l] - 'a'] == bucket[t[l] - 'a']) break;
    				bucket[t[l] - 'a'] ++;
    			}
    			f[i][j] = l - j;
    			if (f[i + 1][l] == a[i + 1].r - a[i + 1].l + 1)
    				g[i][j] = f[i][j] + g[i + 1][l];
    			else g[i][j] = f[i][j] + f[i + 1][l];
    			for (int p = j; p <= l; p++)  // [j,l] 是当前区间绝对可以匹配的,找下一个区间最优匹配 
    			{
    				if (p != l) bucket[t[p] - 'a'] --;
    				if (f[i + 1][p] == a[i + 1].r - a[i + 1].l + 1)
    					ans = max(ans, p - j + g[i + 1][p]);
    				else ans = max(ans, p - j + f[i + 1][p]);
    			}
    		}
    	printf ("%d
    ", ans);
    	return 0;
    }
    

    T4 Vani和Cl2捉迷藏:

    题目大意:

    最大独立集板题。

    正文:

    板题不讲。

    代码:

    const int N = 210, M = 30010;
    
    inline ll Read()
    {
    	ll x = 0, f = 1;
    	char c = getchar();
    	while (c != '-' && (c < '0' || c > '9')) c = getchar();
    	if (c == '-') f = -f, c = getchar();
    	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
    	return x * f;
    }
    
    int n, k;
    
    bool G[N][N];
    
    int con[N];
    bool vis[N];
    
    bool Hungary(int u)
    {
    	for (int v = 1; v <= n; v++)
    	{
    		if (!G[u][v]) continue;
    		if (vis[v]) continue;
    		vis[v] = 1;
    		if (!con[v] || Hungary(con[v]))
    		{
    			con[v] = u;
    			return 1;
    		}
    	}
    	return 0;
    }
    
    int main()
    {
    //	freopen("travel10.in", "r", stdin);
    //	freopen(".out", "w", stdout);
    	n = Read(), k = Read();
    	for (int i = 1, u, v; i <= k; i++)
    		u = Read(), v = Read(), G[u][v] = 1;
    		
    	for (int k = 1; k <= n; k++)
    		for (int i = 1; i <= n; i++)
    			if (i != k)
    				for (int j = 1; j <= n; j++)
    					if (j != i && j != k)
    						G[i][j] |= G[i][k] & G[k][j];
    	int ans = 0;
    	for (int i = 1; i <= n; i++)
    	{
    		memset(vis, 0, sizeof vis);
    		if(Hungary(i)) ans++;
    	}
    	printf ("%d
    ", n - ans);
        return 0;
    }
    
  • 相关阅读:
    Python(2.7.6) 特殊方法
    Python(2.7.6) 列表推导式
    代码神注释鉴赏,喜欢拿去用
    为什么说重启能解决90%的问题
    为什么说重启能解决90%的问题
    编程语言简史
    编程语言简史
    Shell脚本中循环select命令用法笔记
    程序员职业规划
    程序员职业规划
  • 原文地址:https://www.cnblogs.com/GJY-JURUO/p/15000428.html
Copyright © 2020-2023  润新知