【题目记录】——第 45 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(上海)


题目地址 第 45 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(上海)
这次题目稍微简单一些,我们做了三个,B,G,M,本来D题应该能做出来的,但是我当时没有考虑全面,脑子混乱,结果没做出来,最后的

B Mine Sweeper II 思维

题目地址B Mine Sweeper II
题目大意:类似扫雷,有扫雷的规则,不过这个是挖矿,我基于扫雷来说明题意,一个网格,有的地方有雷,有的地方没有雷,没有雷的格子显示这个格子一周8个格子中雷的个数。输入中的.表示没有雷的位置,x表示有雷的位置。给两个mn的网格,让你更改第二个网格中有没有雷的状态,最多更改 ⌊ m n 2 ⌋ \lfloor\frac{mn}{2}\rfloor 2mn次,让第二个网格中所有没有雷的格子上的数字的和等于第一个网格中的数字和。
思路:总之,最后是要么将第二个格网格改成第一个网格一样的,要么改成与第一个网格相反的。有一个规律,如果改成与第一个网格相同需要a次那么改成与第一个网格相反的则需要m
n-a次,同时保证了他们的数字和相同
AC代码:

#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
string strs[1005];
string strs2[1005];
int a[8][2]={{1,0},{1,1},{0,1},{-1,1},{-1,0},{-1,-1},{0,-1},{1,-1}};
int judge(int n,int m)
{
    int ans=0;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            if(strs[i][j]!=strs2[i][j])
                ans++;
        }
    }
    return ans;
}


void print(int n,int m)
{
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            printf("%c",strs[i][j]);
        }
        printf("\n");
    }
}

void printfan(int n,int m)
{
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            if(strs[i][j]=='.')
                printf("X");
            else
                printf(".");
        }
        printf("\n");
    }
}

void solve()
{
    int n,m;
    scanf("%d%d",&n,&m);
    int k=n*m/2;
    for(int i=0;i<n;i++)
    {
        cin>>strs[i];
    }
    for(int i=0;i<n;i++)
    {
        cin>>strs2[i];
    }
    int base=judge(n,m);

    if(base<=k)
    {
        print(n,m);
    }
    else
    {
        printfan(n,m);
    }
}

int main()
{
	int t = 1;
	while(t--)
	{
		solve();
	}
    return 0;
}

D Walker

题目地址D Walker
题目大意:
给定数轴的长度,两个人的初始位置和速度;
两个人在数轴上走路,问两个人路程覆盖整个数轴的最短时间是多少;
思路:
分为三种情况;
第一种,一个人走完全程;
第二种,两个人相对着走完全程;
第三种,一个人走一段,另一个人走另一段,因为子情况太多,所以选择二分这种大情况,p1走[0-mid],p2走[mid-n];
AC代码:

#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <string>
#include <algorithm>
#include <queue>
#include <utility>
#include <stack>
#include <map>
#include <cmath>
#define mes memset 
#define mec memcpy
 
using namespace std;
 
typedef long long ll;
typedef pair<int,int>PII;
 
const int N = 2e6 + 10;
const int null = 0x3f3f3f3f;
const ll mod = 1e9 + 7;

int T;
double n,p1,p2,v1,v2;

int main()
{
	cin >> T;
	while(T --)
	{
		cin >> n >> p1 >> v1 >> p2 >> v2;
		
		if(p1 > p2)
		{
			swap(p1,p2),swap(v1,v2);
		}
		
		double ans = 0;
		ans = min((min(n - p1,p1) + n) / v1,(min(n - p2,p2) + n) / v2);
		ans = min(ans,max((n - p1) / v1,p2 / v2));
		
		double l = p1,r = p2;
		for(int i = 1;i <= 100;++ i)
		{
			double mid = (l + r) / 2;
			
			double ans1 = (min(mid - p1,p1) + mid) / v1;
			double ans2 = (min(n - p2,p2 - mid) + n - mid) / v2;
			ans = min(ans,max(ans1,ans2));
			
			if(ans1 <= ans2) l = mid;
			else r = mid;
		}
		
		printf("%.10lf\n",ans);
	}

	return 0;
}

G Fibonacci 思维+规律

题目地址G Fibonacci
题目大意:斐波那契数列为1,1,2,3,5,8,13,21,…
可以看到,这个数列有以下特点:
奇,奇,偶,奇,奇,偶…
当 x与 y相乘为偶数时,g(x, y) = 1
计算 ∑ i = 1 n ∑ j = i + 1 n g ( f i , f j ) \sum_{i=1}^n\sum_{j=i+1}^{n}g(f_i,f_j) i=1nj=i+1ng(fi,fj)
思路:
当 x或 y中其中一个为偶数时,他们相乘也为偶数。
当 i为偶数时,j从i+1 到 n与它相乘,得到的结果也为偶数。而j 从i+1到 n ,一共有n - i个数,因此就有ans += n - i;
当i为奇数时,若j从i+1到n中,有k个偶数,那么答案也会加k 。
那么这个k怎么求呢?
每三个数中,就有一个数为偶数。在给定的n个数中,就有n/3个数为偶数。
比如,n 等于10 ,该斐波那契数列为 1 , 1 , 2 , 3 , 5 , 8 , 13 , 21 , 34 , 55其中的偶数只有 2 , 8 , 34 ,个数刚好为 10/3=3
因此从第 1到 i个数中,一共有i/3个偶数。从第1 到 n 个数中,一共有n/3个偶数。
那么,从第i+1 到 n 个数中,有 n/3-i/3个偶数,所以k=n/3-i/3
即,当i为奇数时,有 ans += n/3 - i/3​ ;

#include<bits/stdc++.h>

#define int long long
using namespace std;

signed main() {
    int n;
    cin >> n;
    int ans = 0;
    for (int i = 1; i <= n; i++) {
        if (i % 3 == 0) {
            ans += (n - i);
        } else {
            ans += (n / 3 - i / 3);
        }
    }
    cout << ans << endl;
    return 0;
}

M Gitignore (模拟+思维)

题目地址M Gitignore
题目大意:给出n个要删除的文件路径,同时给出m个不能删除的文件路径。每次删除都只能删除一个文件或者一个文件夹(和该文件夹内的所有文件),问最少需要删除多少个路径
思路:这题直接模拟即可,将n个要删除的放在str1组中,将m个不能删除的放在str2组中,先将m个不能删除的所包含的路径全部标记为1,再去处理n个要删除的路径。
当处理到的路径未被标记(即标记为0),那么可以直接删除掉,并将该路径标记为2。
如果处理到的路径标记为1,说明该路径不可被删除。
如果处理到的路径被标记为2,说明该路径已经被删除过不需要再去处理。

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
#include<math.h>
#include<string.h>
#include<string>
#include<map>
using namespace std;
#define ll long long
const int mod = 1e9 + 7;
int n, m;
int t;
int ans;
map<string, int> mp;
string str1[110], str2[110];
int main() {
	cin >> t;
	while (t--) {
		ans = 0;
		mp.clear();
		cin >> n >> m;
		for (int i = 0; i < n; i++)
			cin >> str1[i];
		for (int i = 0; i < m; i++)
			cin >> str2[i];
		for (int i = 0; i < m; i++) {
			int sz = str2[i].size();
			string tmp = "";
			for (int j = 0; j < sz; j++) {
				tmp += str2[i][j];
				if (str2[i][j] == '/') {
					mp[tmp] = 1;   //标记为不可删除
				}
			}
		}
		ans = n;
		for (int i = 0; i < n; i++) {
			int sz = str1[i].size();
			string tmp = "";
			for (int j = 0; j < sz; j++) {
				tmp += str1[i][j];
				if (str1[i][j] == '/') {
					if (mp[tmp] == 0)   //当tmp可以删除时
						mp[tmp] = 2;
					else if (mp[tmp] == 2) {  //当再次遇到可以删除的tmp时
						ans--;
						break;
					}
				}
			}
		}
		cout << ans << endl;
	}
	return 0;
}