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 把枪里选择一把枪。
关于比赛有如下规定:
- 他俩第一枪一定是同时开的
- 能开枪就开枪
- 如果两人同时死亡,各有 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;
}

浙公网安备 33010602011771号