7.30 18级杭电多校第四场

比赛过程

  开局被物理题唬住了,以为是个积分题,发现过的人很多,分析之后才发现猫腻,反应有点慢了。1002 wa的比较多,感觉是写法有点繁琐,出现了不容易发现的bug,“水题大作”一直是一个痛点。。。1005也算是个简单题吧,但是刚开始没读清题,wa了一发,之后又少考虑了情况,又wa了一发。1007比较可惜,3点多就反应出来是二分图最小覆盖问题,结果没去找算法,而是想手写,没写出来。。前面我们一直采用简单题单开,然后中期两个人看一道,一个人去开另一道,一直到1005出来还算好,但是一个人单开1004却卡了很久,一直到最后一个小时的时候还是两个人看1007一个人看1004,结果导致最后发现1007方法错误想要去做1004的时候已经没时间看懂队友的代码。
  总的来看感觉21分的效果还可以,但是还是感觉需要一个自由人,俩人各开一道题写,剩下一个两个都看,等俩人写完之后检查一下代码再交,应该对于wa的情况有所帮助。

题解

1002

题意

  俩人对枪,有多把枪可选,每把枪都有伤害和装填时间两种属性,如果俩人同时死亡的话你有 50 % 50\% 50% 的几率取胜,问在对方随机选枪的情况下,你最大的获胜概率。

解法

  水题,算一下最快打死对方的枪有几把,稍微计算一下就可以。

代码
#include <bits/stdc++.h>
#define FOR(a,b,c) for(int a=b;a<=c;a++)
#define RFOR(a,b,c) for(int a=b;a>=c;a--)
#define IO ios::sync_with_stdio(false), cin.tie(0)
#define endl '\n'
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 2e5 + 5;
int main(){
    IO;
    int t;
    cin >> t;
    while(t--){
        int n;
        cin >> n;
        map<int, int> mp;
        int minn = inf;
        FOR(i,1,n){
            int x, y;
            cin >> x >> y;
            int tmp = (ceil(100.0 / x) - 1) * y;
            mp[tmp]++;
            minn = min(minn, tmp);
        }
        double ans = mp[minn] * 0.5 / n;
        printf("%.6f\n", 1 - ans);
    }
    return 0;
}

1004

题意

  有n个点m条边的无向图,每条边有自己的长度(即通过时间)。每个点有不同的手势要求,切换手势要x的时间,求从起点到中终点的最短时间。

解法

  比赛时第一个看的是这道题,分析了大概问题在于要拆点,就去做签到提了,当时只是觉得要把M点拆成一左一右两个点,后面看人家题解可以把每个点都拆成俩分别建边,空间复杂度居然吃的消,然后补题的时候因为存边的数组开小了(居然要乘8倍,而且开小了还T),然后还被strlen函数坑了一把,有一说一这玩意复杂度要是放在循环里可吃不消,这也是一个T的原因,总结来说这道题就是一个拆点+dijjiskra,但是边的空间大小这里比较坑。

代码
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <iomanip>
#include <string>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <fstream>
#include <unordered_map>
using namespace std;
#define ms(a, x) memset(a, x, sizeof(a))
#define fore(i, a, n) for (ll ll i = a; i < n; i++)
#define ford(i, a, n) for (ll ll i = n - 1; i >= a; i--)
#define si(a) scanf("%d", &a)
#define sl(a) scanf("%lld", &a)
#define sii(a, b) scanf("%d%d", &a, &b)
#define siii(a, b, c) scanf("%d%d%d", &a, &b, &c)
#define sll(a, b) scanf("%lld%lld", &a, &b)
#define slll(a, b, c) scanf("%lld%lld%lld", &a, &b, &c)
#define ss(a) scanf("%s", a);
#define debug(a) cout << a << endl
#define pr(a) printf("%d ", a)
#define endl '\n'
#define pi acos(-1.0)
#define tr t[root]
#define IO ios::sync_with_stdio(false), cin.tie(0)
#define ull unsigned long long
#define py puts("Yes")
#define pn puts("No")
#define pY puts("YES")
#define pN puts("NO")
#define re(i, a, b) for (int i = a; i <= b; ++i)
#define de(i, a, b) for (int i = a; i >= b; --i)
#define all(x) (x).begin(), (x).end()
#define ls(x) x.resize(unique(all(x)) - x.begin())
const double eps = 1e-3;
inline int sgn(const double &x) { return x < -eps ? -1 : x > eps; }
typedef long long ll;
typedef pair<ll, int> pli;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const ll INF = 0x3f3f3f3f;
template <class T>
inline void cmin(T &a, T b) { ((a > b) && (a = b)); }
template <class T>
inline void cmax(T &a, T b) { ((a < b) && (a = b)); }
long long PRIMES[223] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409};
const int MAXN = 8e5 + 10;
const ll mode = 1e9 + 9;
ll Pow(ll a, ll b)
{
  ll sum = 1;
  a = a % mode;
  while (b > 0)
  {
    if (b % 2 == 1) //判断是否是奇数,是奇数的话将多出来的数事先乘如sum
      sum = (sum * a) % mode;
    b >>= 1;
    a = (a * a) % mode; // 不断的两两合并再取模,减小a和b的规模
  }
  return sum;
}
//-----------------------------------------------------------------------------------------

int n, m, s, t, xx;
long long d[MAXN];
int head[MAXN],ver[4 * MAXN],edge[4 * MAXN], Next[4 * MAXN];//开两倍存储双向边 
bool v[MAXN];
int tot=0;
priority_queue<pair<long long,int> >q;//这里别忘long long 
int hand[MAXN];
char S[100005];
void add(int x,int y,int z)
{
    ver[++tot]=y;
    edge[tot]=z;
    Next[tot]=head[x];
    head[x]=tot;
}
long long dijkstra(int s, int t)
{
    long long ans = 1e18;
    for(int i = 1; i <= 2 * n; i++) d[i] = 1e18;
    memset(v, 0, sizeof(v));
    d[s]=0;
    q.push(make_pair(0,s));
    int i,j;
    while(q.size())
    {
        int x=q.top().second;
        q.pop();
        if(v[x])continue;
        v[x]=1;
        for(i=head[x];i;i=Next[i])
        {
            int y=ver[i],z=edge[i];
            if(hand[x] != hand[y]) z += xx;//是否要换手 
            if(d[y]>d[x]+z)
            {
                d[y]=d[x]+1ll * z;
                q.push(make_pair(-d[y],y));
            }
        }
    }
    return min(d[t], d[t + n]);
}

signed main()
{
  int T;
  si(T);
  while (T--)
  {
    siii(n,m,s);
    sii(t,xx);
    ss(S);
    tot = 0;
    re(i, 1, 2 * n) head[i] = 0;
    int l=strlen(S);
    for (int i = 0; i <l ; i++)
    {
      if (S[i] == 'L')
      {
        hand[i + 1] = hand[i + 1 + n] = 0;
      }
      else if (S[i] == 'R')
      {
        hand[i + 1] = hand[i + 1 + n] = 1;
      }
      else
      {
        hand[i + 1] = 0;
        hand[i + 1 + n] = 1;
      }
    }
    re(i, 1, m)
    {
      int u, v, w;
      siii(u, v, w);
      add(u, v, w);
      add(v, u, w);
      add(u + n, v, w);
      add(v, u + n, w);
      add(u, v + n, w);
      add(v + n, u, w);
      add(u + n, v + n, w);
      add(v + n, u + n, w);
    }
    ll ans = min(dijkstra(s,t), dijkstra(s + n,t));
    printf("%lld\n", ans);
  }
  return 0;
}

1005

题意

  有俩字符串 a , b a,b a,b,如果这两个字符串包含的字符种类数量一样,且所有字符 x x x a , b a,b a,b 中的第 i i i 次出现的位置相差不超过 1,则说明这俩字符串大致相等,问你有多少和给出的字符串大致相等的字符串(包含自己)。

解法

  算是个简单题把,易得其实就是让你交换相邻的不同字符,注意一个字符只能换一次,也可以不换,只要你先把字符串分段,分界点是相同的字符,比如 a b c d d e f abcddef abcddef 需要分成 a b c d abcd abcd d e f def def 两段,再把这两段的交换种类相乘即可。
  发现长度为 l e n len len 的一段的交换种类其实只和 l e n len len 有关,所以要 DP 预处理, d p [ i ] dp[i] dp[i] 代表长度为 i i i 的段具有的交换种类,状态转移方程比较好想:
d p [ i ] = ( d p [ i − 1 ] + d p [ i − 2 ] + 1 ) % m o d dp[i]=(dp[i-1]+dp[i-2]+1)\%mod dp[i]=(dp[i1]+dp[i2]+1)%mod   其中 d p [ i − 1 ] dp[i-1] dp[i1] 是如果第 i i i 位不参与交换的种类, d p [ i − 2 ] dp[i-2] dp[i2] i i i i − 1 i-1 i1 位交换的种类,最后还要加上只有 i i i i − 1 i-1 i1 位交换的种类,也就是 1,举个 n = 5 n=5 n=5 的例子就明白了。

代码
#include <bits/stdc++.h>
#define FOR(a,b,c) for(int a=b;a<=c;a++)
#define RFOR(a,b,c) for(int a=b;a>=c;a--)
#define IO ios::sync_with_stdio(false), cin.tie(0)
#define ll long long
#define endl '\n'
using namespace std;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int maxn = 2e5 + 5;
vector<int> v;
map<string, int> mp;
ll cal[maxn];
int main(){
    IO;
    int t;
    cin >> t;
    cal[1] = 0; cal[2] = 1;
    FOR(i,3,maxn-1){
        cal[i] = (cal[i - 1] + cal[i - 2] + 1) % mod;
    }
    while(t--){
        int n;
        cin >> n;
        v.clear(), mp.clear();
        int cnt = 0;
        FOR(i,1,n){
            string s;
            cin >> s;
            if(!mp[s]){
                mp[s] = ++cnt;
                v.push_back(cnt);
            }
            else v.push_back(mp[s]);
        }
        int m = v.size();
        int f = 0;
        ll ans = 1;
        int len = 1;
        vector<int> duan;
        FOR(i,1,m-1){
            if(v[i]!=v[i-1]){
                len++;
                f = 1;
            }
            if(v[i]==v[i-1]||i==m-1){
                if(f){
                    duan.push_back(len);
                    len = 1;
                    f = 0;
                }
            }
        }
        for(auto i:duan){
            ans = ans * (cal[i] + 1) % mod;
        }
        cout << ans << endl;
    }
    return 0;
}

1007

题意

  翻译过来就是:给你几对数,假如是 x , y x,y x,y,这一对数可以选择归属 x + y x+y x+y组,或选择归属 x − y x-y xy组,没有该组就创建一个组,问你怎么选择归属才能让组数最少。

解法

  其实你可以把每一对数的 x + y x+y x+y x − y x-y xy 都算出来,分别离散化一下,之后把 x + y x+y x+y 放左边, x − y x-y xy 放右边,中间根据输出的 n n n 个数据连 n n n 条边,然后问题就转换成了二分图最小点覆盖问题,有一个结论为:二分图的最小点覆盖等于二分图的最大匹配。所以求出这个二分图的最大匹配即可。感觉建图比较巧,但是仔细想想也挺有道理。

代码
#include<iostream>
#include<cmath>
#include<algorithm>
#include<queue>
#include<map>
#include<unordered_map>
#include<vector>
#include<stack>
#include<string>
#include<cstring>
#include<cstdio>
#include<utility>
#define ll long long
#define ull unsigned long long
#define IO ios::sync_with_stdio(false), cin.tie(0)
#define endl '\n'
#define pi acos(-1)
#define lowbit(x) ((x)&(-(x)))
#define debug(x) cout<<x<<'\n'
#define FOR(a,b,c) for(int a=b;a<=c;a++)
#define RFOR(a,b,c) for(int a=b;a>=c;a--)
#define debug(x) cout<<x<<'\n'
#define all(x) (x).begin(), (x).end()
#define ls(x) x.resize(unique(all(x)) - x.begin())
using namespace std;
typedef pair<int,int> P;
typedef pair<double,double> Pd;
const int dx[] = {-1, 0, 1, 0};
const int dy[] = {0, 1, 0, -1};
const ll INF=0x3f3f3f3f3f3f3f3f;
const int inf = 0x3f3f3f3f;
const ll mod = 1e9+7;
const double eps = 1e-11;
ll gcd(ll a, ll b) {return b==0?a:gcd(b, a%b);}
ll lcm(ll a, ll b) {return a/gcd(a, b)*b;}
ll mul(ll a,ll b){ll ans=0;a%=mod,b%=mod;while(b) { if(b&1) ans = (ans+a)%mod; a = (a*2)%mod; b >>= 1; }return ans;}
ll powmod(ll a,ll b){ll ans = 1;a %= mod;b%=(mod-1);while(b){if(b & 1){ans = ans * a % mod;b--;}b >>= 1;a = a * a % mod;}return ans;}
//(b/a)%p=b*a^(p-2)%p
int pr(ll num){if(num == 1) return 0;if(num ==2|| num==3 ) return 1 ;if(num %6!= 1&&num %6!= 5) return 0 ;int tmp =sqrt( num);for(int i= 5;i <=tmp; i+=6 )if(num %i== 0||num %(i+ 2)==0 )return 0 ;return 1 ;}
int Day(int y,int m, int d){if(m==1||m==2) { m+=12; y--; }int w=(d+2*m+3*(m+1)/5+y+y/4-y/100+y/400)%7;return w+1;}
ll C(ll n,ll m) {if(n < m) return 0;ll res = 1;for(int i=1; i<=m; i++) {ll a = (n+i-m)%mod;ll b = i%mod;res = res*(a*powmod(b,mod-2)%mod)%mod;}return res;}
ll Lucas(ll n,ll m) {if(m == 0) return 1;return C(n % mod, m % mod) * Lucas(n / mod, m / mod) % mod;}
//long long PRIMES[223] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409};
//const int maxn=2e7+5;
//ll v[maxn] = {0}, prime[maxn], Cnt = 0;
//void getpri(ll n) {for (ll i = 2; i <= n; ++i) {if (!v[i]) { v[i] = i; prime[++Cnt] = i;}for (ll j = 1; j <= Cnt; ++j) {if (prime[j] > v[i] || prime[j] * i > n) break; v[i * prime[j]] = prime[j];}}}
const int maxn=2e5+15;
struct ac{
    int x, y;
} a[maxn];
int cnt;
int n, m, s, t;
bool vis[maxn];
ll d[maxn], cur[maxn];
struct Edge {
    int u, v;
    ll cap, flow;
} e[maxn*6];    
vector<ll> G[maxn];
void init(int n) {
    cnt = 0;
    for (int i = 0 ; i <= n ; i ++) G[i].clear();
}
void add(int u, int v, ll cap, ll f) {
    e[cnt] = Edge{u, v, cap, f};
}
void AddEdge(int u, int v, ll cap) {
	add(u, v, cap, 0);
    G[u].push_back(cnt++);
    add(v, u, 0, 0);
    G[v].push_back(cnt++);
}
bool BFS() {
	fill(vis, vis + 2 * n + 6, 0);
	queue<ll> q; q.push(s);
    vis[s] = 1; d[s] = 0;
    while (!q.empty()) {
        int v = q.front(); q.pop();
        for (int i = 0; i < G[v].size(); i++) {
            Edge &te = e[G[v][i]];
            if (!vis[te.v] && te.cap > te.flow) { 
                vis[te.v] = 1;
                d[te.v] = d[v] + 1;
                q.push(te.v);
            }
        }
    }
    return vis[t];
}
ll dfs(int x, ll a) {
    if (x == t || a == 0) return a;
    ll flow = 0, f;
    for (ll &i = cur[x]; i < G[x].size(); i++) { 
        Edge &te = e[G[x][i]];
        if (d[x] + 1 == d[te.v] && (f = dfs(te.v, min(a, te.cap - te.flow))) > 0) {
            te.flow += f;
            e[G[x][i]^1].flow -= f;
            flow += f;
            a -= f;
            if (a == 0) break;
        }
    }
    return flow;
}
ll Dinic() {
    ll flow = 0;
    while (BFS()) {
        fill(cur, cur + 2 * n + 6, 0);
		flow += dfs(s, inf);
    }
    return flow;
}

int main(){
    IO;
    int T;
    cin >> T;
    while(T--){
        cin >> n;
        map<ll, int> ls1, ls2;
        vector<int> be, end;
        int cnt1 = 1, cnt2 = 1;
        FOR(i,1,n){
            int x, y;
            cin >> x >> y;
            a[i].x = x, a[i].y = y;
            if(!ls1[x+y]) ls1[x + y] = cnt1++, be.push_back(ls1[x + y]);
            if(!ls2[x-y]) ls2[x - y] = cnt2++, end.push_back(ls2[x - y]);
        }
		init(2 * n + 5);
        s = 0, t = 2 * n + 4;
        for(auto i:be){
            AddEdge(s, i, 1);
        }
        FOR(i,1,n){
            int u, v;
            u = ls1[a[i].x + a[i].y];
            v = ls2[a[i].x - a[i].y];
            AddEdge(u, v + n, 1);
        }
        for(auto i:end){
            AddEdge(i + n, t, 1);
        }
		ll ans = Dinic();
		cout << ans << endl;
    }
    return 0;
}

1011

题意

  给你俩球的质量和初始距离 d d d,这俩球只受相互的万有引力,问你 t t t 时刻这俩球相聚多远, e p s = 1 e − 6 . eps=1e{-6}. eps=1e6.

解法

  很奇葩的一道题,我还以为是积分问题,后来看到 t t t 最大才是100,生活常识告诉我100秒内俩球相互吸引的距离可以忽略不计。保险点就输出 d − 0.000001 d-0.000001 d0.000001,其实直接输出 d d d 就能过。

代码
#include <bits/stdc++.h>
using namespace std;
#define FOR(a,b,c) for(int a=b;a<=c;a++)
#define RFOR(a,b,c) for(int a=b;a>=c;a--)
#define IO ios::sync_with_stdio(false), cin.tie(0)
#define endl '\n'
const int maxn = 2e5 + 5;
int main(){
    IO;
    int t;
    cin >> t;
    while(t--){
        double a, b, c, d;
        cin >> a >> b >> c >> d;
        printf("%.20f\n", c );
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值