7.30 2020 Multi-University Training Contest 4题解及补题

7.30 2020 Multi-University Training Contest 4题解及补题

比赛过程

开局1011找到规律还是比较顺利的,1002杀掉100血,情况欠考虑,1005注意分好情况

题解

1002 Blow up the Enemy

题意

有对父子在玩枪战游戏,有 n 把枪,,每把枪都有两个属性 A :攻击力 ,D:冷却时间。

初始都有 100 滴血,父亲会随机从 n 把枪里选择一把枪。

关于比赛有如下规定:

  1. 他俩第一枪一定是同时开的
  2. 能开枪就开枪
  3. 如果两人同时死亡,各有 50 % 的概率获胜

现在要你为儿子选择一把枪,使得其胜利的概率最大,输出这个概率

解法

直接判断杀掉 100 滴血最快的枪有几把,输出 \(1.0−x/2n\)

代码

#include <algorithm>
#include <bitset>
#include <cctype>
#include <cerrno>
#include <clocale>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <limits>
#include <list>
#include <map>
#include <iomanip>
#include <ios>
#include <iosfwd>
#include <iostream>
#include <istream>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <utility>
#include <vector>
#include <cwchar>
#include <cwctype>
using namespace std;
#define IO ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
const int inf = 0x3f3f3f3f;
typedef long long ll;
const int maxn = 100500;
const ll mod = 1e9 + 7;
typedef pair<int,int> pii;
const double pi = acos(-1);
struct node
{
    int x,y;
    // double c;
    int c;
}a[2005];
bool cmp(node a,node b) {
    return a.c<b.c;
}
int main() {
    IO;
    int T,n;
    cin>>T;
    while(T--) {
        cin>>n;
        bool flag=false;
        int cnt=0;
        for(int i=0;i<n;i++) {
            cin>>a[i].x>>a[i].y;
            int cn=100-a[i].x;
            if(a[i].x>=100) {flag=true; cnt++;}
            // a[i].c=double(a[i].x*1.0/a[i].y);
            if(cn>0) {
                if(cn%a[i].x!=0) {
                    a[i].c=a[i].y*(cn/a[i].x+1);
                }
                else {
                    a[i].c=a[i].y*(cn/a[i].x);
                }
            }
        }
        double ans=0.0;
        if(flag==false) {
            int tem=1;
            sort(a,a+n,cmp);
            int te=a[0].c;
            for(int i=1;i<n;i++) {
                if(a[i].c==te) {
                    // cout<<a[i].c<<" "<<te<<endl;
                    tem++;
                }
                else break;
            }
            ans=1.0-(0.5*tem*1.0/(n*1.0));
        }
        else {
            ans=1.0-(0.5*cnt*1.0/(n*1.0));
        }
        cout<<fixed<<setprecision(6)<<ans<<endl;
    }
    return 0;
}

1003 Contest of Rope Pulling

题意

T 组数据,有n,m代表每个班级的人数,每个人有两种属性wi(力量值),vi(魅力值),
问你从两班中选择两个子集(可为空),使得两个子集的力量值和相等,求选出来的所有人的魅力值和的最大值

解法

可以将两班人和为一个集合,需要将第二班的力量改为负数。之后进行dp,那么dp[0]就是答案,由于下标可能是负数所以需要加一个数表示0
需要注意的是初始化为-INF,其次就是注意一下不要超过数组的范围。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 3e3 + 7;
const ll M = 1e5 + 7;
const ll INF = 1e18;
inline int read()
{
    int 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;
}
int t;
int n, m;
struct node{
    ll w, v;
};
node a[N];
ll dp[M];

ll getdp(int n)
{
    fill(dp, dp + M, -INF);
    dp[50000] = 0;

    for (int i = 1; i <= n;i++)
    {
        if(a[i].w >= 0)
        {
            for (int j = 1e5; j >= a[i].w;j--)
            {
                if(dp[j - a[i].w] != -INF) dp[j] = max(dp[j], dp[j - a[i].w] + a[i].v);
            }
        }
        else
        {
            int lim = 1e5 + a[i].w;
            for (int j = 0; j <= lim; j++)
            {
                if (dp[j - a[i].w] != -INF) dp[j] = max(dp[j], dp[j - a[i].w] + a[i].v);
            }
        }
        
    }
    return dp[50000];

}

int main()
{
    srand(time(0));
    t = read();
    while(t--)
    {
        n = read(), m = read();
        for (int i = 1; i <= n + m;i++) 
        {
            a[i].w = read(), a[i].v = read();
            if(i > n) a[i].w = -a[i].w;
        }
        random_shuffle(a + 1, a + n + m + 1);
        ll ans = 0;
        ans = getdp(n + m);
        printf("%lld\n", ans);
    }
    return 0;
}

1004 Deliver the Cake

题意

给定一张无向图,求从起点到终点的最短路径。其中,每个点有一定限制,规定在该点时必须是以下三种状态之一:L,R,M
经过L点时必须左手拿蛋糕,经过R点时必须右手拿蛋糕,经过M点时左手右手都可以。
在路径中可以进行任意次换手,每次换手花费 x 。

解法

拆点+dij。这个题还是比较有意思的,我们也学习了拆点的技巧,将必须左手的村庄拆成两个左手,右手拆成两个右手,M的村庄拆成一左一右,然后跑dijsktra,然后因为是双向边,拆点后点数量变为原来2倍,连边情况变为原来的4倍,所以存边的数组要开8倍;

代码

#include<bits/stdc++.h>
using namespace std;
#define closeSync ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define repp(i,a,b) for(int i=a;i<b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define perr(i,a,b) for(int i=a;i>b;i--)
typedef long long ll;
typedef pair<int,int> P;
const int INF=0x3f3f3f3f;
const ll LINF=0x3f3f3f3f3f3f3f3f;
const ll mod=998244353;
const int maxn=200010;
char ss[maxn],sss[maxn];
int n,m,s,t,x;
ll dis[maxn];
int head[maxn],tot;
struct node
{
    int u,v,nxt;
    ll w;
}e[8*maxn];
struct qnode
{
    int v;
    ll dis;
    bool operator < (const qnode &r)const
    {
        return dis>r.dis;
    }
};
void add(int u,int v,ll w)
{
    e[tot].u=u;
    e[tot].v=v;
    e[tot].w=w;
    e[tot].nxt=head[u];
    head[u]=tot++;

    e[tot].u=v;
    e[tot].v=u;
    e[tot].w=w;
    e[tot].nxt=head[v];
    head[v]=tot++;

}
void init()
{
    rep(i,1,2*n)head[i]=-1;
    tot=0;
}
ll dij(int s)
{
    rep(i,1,2*n)dis[i]=LINF;
    priority_queue<qnode>q;
    dis[s]=0;
    q.push({s,0});
    qnode tmp;
    while(!q.empty())
    {
        tmp=q.top();
        q.pop();
        int u=tmp.v;
        if(tmp.dis>dis[u])continue;
        for(int i=head[u];i!=-1;i=e[i].nxt)
        {
            int v=e[i].v;
            ll w=e[i].w;
            ll z=(sss[u]==sss[v]?0:x);
            if(dis[u]+w+z<dis[v])
            {
                dis[v]=dis[u]+w+z;
                q.push({v,dis[v]});
            }
        }
    }
    return min(dis[t],dis[t+n]);
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d%d%d",&n,&m,&s,&t,&x);
        init();
        scanf("%s",ss);
        rep(i,1,n)
        {
            if(ss[i-1]=='M')sss[i]='L',sss[i+n]='R';
            else if(ss[i-1]=='L')sss[i]=sss[i+n]='L';
            else sss[i]=sss[i+n]='R';
        }
        while(m--)
        {
            int u,v;
            ll w;
            scanf("%d%d%lld",&u,&v,&w);
            add(u,v,w);add(u+n,v,w);
            add(u+n,v+n,w);add(u,v+n,w);
        }

        printf("%lld\n",min(dij(s),dij(s+n)));
    }
    return 0;

}

1005 Equal Sentences

题意

对句子S中的单词向前移一位或向后移一位或不移得到的两个句子几乎相等,求多少不同的句子,几乎等于S,包括S本身

解法

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll mod=1e9+7;
int main(){
    ll t;
    scanf("%lld",&t);
    while(t--){
        ll n;
        scanf("%lld",&n);
        string s[n];
        ll a[n],c[n];
        for(ll i=0;i<n;i++){
            cin>>s[i];
            a[i]=0;
            c[i]=0;
        }
        if(n==1){
            cout<<1<<endl;
            continue;
        }
        ll ans=1;
        if(s[n-1]!=s[n-2]){
            c[n-2]=2;
        }
        else{
            c[n-2]=1;
        }
        if(n-2==0){
            cout<<c[0]<<endl;
            continue;
        }
        if(s[n-3]!=s[n-2]){
            c[n-3]=c[n-2]+1;
        }
        else{
            c[n-3]=c[n-2];
        }
        if(n-3==0){
            cout<<c[0]<<endl;
            continue;
        }
        for(ll i=n-4;i>=0;i--){
            if(s[i]!=s[i+1]){
                c[i]=(c[i+2]+c[i+1])%mod;
            }
            else{
                c[i]=c[i+1];
            }
        }
        cout<<c[0]<<endl;
    }
    return 0;
}

1007 Go Running

题意

有一条路可以看成是无尽头的数轴,学生可以选择一个点开始跑步,可以选择从任意时间t1开始跑,从任意时间t2结束跑步,也可以选择跑步方向,但跑步速度恒定为1 m/s
跑步开始前不会出现在数轴上,跑步结束后也不会出现在数轴上
这条路上有一些监控,你收到了n份报告,每份报告有两个数据xi和ti,表示时间为ti秒时在数轴的xi位置有至少一个学生在跑步,问最少有多少个学生在跑步

解法

二分图最大匹配问题
假设报告时刻为t,位置为x,那么相同的t+x或者t−x能够合并成一个人。可以用map记录序号,将t+x和t−x相连,再用HK算法求一下最大匹配就好了。

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 5e5 + 10;
const int INF = 0x3f3f3f3f;
vector<int> G[maxn];
int uN;
int Mx[maxn], My[maxn];
int dx[maxn], dy[maxn];
int dis;
bool used[maxn];
bool SearchP() {
	queue<int>Q;
	dis = INF;
	memset(dx, -1, sizeof(dx));
	memset(dy, -1, sizeof(dy));
	for (int i = 1; i <= uN; i++)
		if (Mx[i] == -1) {
			Q.push(i);
			dx[i] = 0;
		}
	while (!Q.empty()) {
		int u = Q.front();
		Q.pop();
		if (dx[u] > dis)break;
		int sz = G[u].size();
		for (int i = 0; i < sz; i++) {
			int v = G[u][i];
			if (dy[v] == -1) {
				dy[v] = dx[u] + 1;
				if (My[v] == -1)dis = dy[v];
				else {
					dx[My[v]] = dy[v] + 1;
					Q.push(My[v]);
				}
			}
		}
	}
	return dis != INF;
}
bool DFS(int u) {
	int sz = G[u].size();
	for (int i = 0; i < sz; i++) {
		int v = G[u][i];
		if (!used[v] && dy[v] == dx[u] + 1) {
			used[v] = true;
			if (My[v] != -1 && dy[v] == dis)continue;
			if (My[v] == -1 || DFS(My[v])) {
				My[v] = u;
				Mx[u] = v;
				return true;
			}
		}
	}
	return false;
}
int MaxMatch() {
	int res = 0;
	memset(Mx, -1, sizeof(Mx));
	memset(My, -1, sizeof(My));
	while (SearchP()) {
		memset(used, false, sizeof(used));
		for (int i = 1; i <= uN; i++)
			if (Mx[i] == -1 && DFS(i))
				res++;
	}
	return res;
}
map<int, int> m1, m2;
int t, n, tt, xx;
int main() {
	scanf("%d", &t);
	while (t--) {
		memset(G, 0, sizeof(G));
		m1.clear();
		m2.clear();
		scanf("%d", &n);
		int u = 0, v = 0;
		for (int i = 1; i <= n; i++) {
			scanf("%d%d", &tt, &xx);
			int x = tt + xx;
			int y = tt - xx;
			if (!m1[x]) m1[x] = ++u;
			if (!m2[y]) m2[y] = ++v;
			G[m1[x]].push_back(m2[y]);
		}
		uN = u;
		printf("%d\n", MaxMatch());
	}
	return 0;
}

1011 Kindergarten Physics

题意

质量a,b的物体,初始距离d米,c秒后的距离

解法

水题,直接输出d或者,可以魔鬼-0.0000000001,小于精确度的

代码

#include<bits/stdc++.h>
using namespace std;
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        double a,b,c,d;
        scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
        c-=0.0000000001;
        printf("%.10lf\n",c);
    }
}

1012 Last Problem

题意

给出一个无限大的二维平面,需要在平面内进行染色,每次可以选择一个点 ( x , y ) 将其染色为 n 的前提是,相邻四个格子必须分别已经染了 n - 1 , n - 2 , n - 3 , n - 4 四种颜色,染色可以覆盖,构造出一种合理的染色方案,使得可以在平面上出现颜色 n

解法

构造题,对于某一时刻

​ n-1

n-2 n n-3

​ n-4

代码

#include <algorithm>
#include <bitset>
#include <cctype>
#include <cerrno>
#include <clocale>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <limits>
#include <list>
#include <map>
#include <iomanip>
#include <ios>
#include <iosfwd>
#include <iostream>
#include <istream>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <utility>
#include <vector>
#include <cwchar>
#include <cwctype>
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const int N=2e3+100;
const int b[5][2]={0,0,0,-1,-1,0,1,0,0,1};
int maze[N][N];
int cnt=0;
void dfs(int x,int y,int val)
{
	if(val<=0)
		return;
	for(int i=1;i<=4;i++)
	{
		int xx=x+b[i][0],yy=y+b[i][1];
		if(maze[xx][yy]!=val-i)
			dfs(xx,yy,val-i);
	}
	maze[x][y]=val;
	printf("%d %d %d\n",x,y,val);
}
 
int main()
{
	int n;
	scanf("%d",&n);
	dfs(1000,1000,n);
    return 0;
}
posted @ 2020-08-09 22:16  cugbacm03  阅读(197)  评论(0)    收藏  举报