zoukankan      html  css  js  c++  java
  • 【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;
    }
    
  • 相关阅读:
    53. Maximum Subarray
    64. Minimum Path Sum
    28. Implement strStr()
    26. Remove Duplicates from Sorted Array
    21. Merge Two Sorted Lists
    14. Longest Common Prefix
    7. Reverse Integer
    412. Fizz Buzz
    linux_修改域名(centos)
    linux_redis常用数据类型操作
  • 原文地址:https://www.cnblogs.com/GJY-JURUO/p/15000428.html
Copyright © 2011-2022 走看看