2022 Hubei Provincial Collegiate Programming Contest 个人向训练记录

 
A. Nucleic Acid Test
题意:给定一张有$n$个点,$m$条边的带边权的无向图,其中有$k$个关键点,要求从其中一个关键点出发经过所有点最后回到任意一个关键点,到任意一个点时距离上次到达关键点的时间不大于给定值$T$,两点间边权代表两点距离,求最小整数速度$V$使得能够满足要求,如不存在,输出$-1$。
 
数据范围:$1\le{n}\le300$, $1\le{m}\le{\frac{n*(n-1)}{2}}$, $1\le{k}\le{n}$, $0\le{T}\le1e9$
 
思路:设两关键点间的最大最短距离为$S_1$,从一个关键点到非关键点再回到任意一个关键点的最短距离的最大值为$S_2$,那么所求$V=⌈MAX(S_1,S_2)/T⌉$。考虑$n$很小,我们可以先预处理出两点间的最小距离。对于非关键点$x$,设求到其余关键点的距离为$L_1,L_2,L_3...,L_k$,其中设$L=MIN(L_1,L_2,...L_k)$,那么有$Len=2*L\le{L_i+L_j} (1\le{i,j}\le{k})$, $S2=2*MAX(Len_1,Len_2...,Len_{(n-k)})$ 。对于关键点,考虑将以关键点为新点重建图,求最小生成树,$S1$即为生成树中边权的$MAX$,注意特判图不连通和$T$为$0$的特殊情况。
#include <bits/stdc++.h>
#define ft first
#define sd second
#define pb push_back
#define MP make_pair
#define ll long long
#define ld long double
#define pll pair<ll,ll>
#define lowbit(a) ((a)&-(a))
#define ull unsigned long long
#define all(x) x.begin(),x.end()
#define nps fixed<<setprecision(10)<<
#define mem(a,k) memset(a,k,sizeof(a))
#define debug(x) cout<<#x<<"="<<x<<endl
#define rep(i,a,b) for(ll i=(a);i<=(b);i++)
#define per(i,a,b) for(ll i=(a);i>=(b);i--)
const ll N=1e6+10;
const ll mod1=1e9+7;
const ll mod2=998244353;
using namespace std;
ll t,n,m,k,tt,tp,sum,ans,res,cnt;
ll a[500][500],b[500],pre[500];
struct node
{
    ll u,v,w;
    bool operator<(const node& i)const{
        return w<i.w;}
}edge[500*500];
void init()
{
    rep(i,1,n)pre[i]=i;
    return ;
}
ll find(ll x)
{
    if(pre[x]==x)return x;
    return pre[x]=find(pre[x]);
}
bool unite(ll x,ll y)
{
    if(find(x)!=find(y))
    {
        pre[find(y)]=find(x);
        return true;
    }
    return false;
}
void Kruskal()
{
    init();
    sort(edge+1,edge+tt+1);
    rep(i,1,tt)
    {
        if(unite(edge[i].u,edge[i].v))
        {
            ans=max(ans,edge[i].w);
            ++cnt;
            if(cnt==k-1)break;
        }
    }
    if(cnt!=k-1)ans=1e18;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr),cout.tie(nullptr);
    //IO
    double t;
    cin>>n>>m>>k;
    cin>>t;
    rep(i,1,n)rep(j,1,n)if(i!=j)a[i][j]=1e18;
    rep(i,1,m)
    {
        ll u,v,w;
        cin>>u>>v>>w;
        a[u][v]=a[v][u]=w;
    }
    rep(i,1,k)
    {
        ll x;
        cin>>x;
        b[x]=1;
    }
    ans=0;
    rep(kk,1,n)rep(i,1,n)rep(j,1,n)a[i][j]=min(a[i][j],a[i][kk]+a[kk][j]);
    rep(i,1,n)
    {
        if(!b[i])
        {
            ll minn=1e18;
            rep(j,1,n)if(b[j])minn=min(minn,2*a[i][j]);
            ans=max(ans,minn);
        }
        else
        {
            rep(j,1,n)if(b[j]&&i!=j)edge[++tt]={i,j,a[i][j]};
        }
    }
    Kruskal();
    if(ans==1e18||!t)cout<<-1;
    else cout<<(ll)ceil(((double)ans)/t);
}
/*






*/
View Code

 

Problem B&C. Potion
题意:有一个容积为$a+b$ 的量筒,量筒只有一个容积为$a$的刻度线,现有两种液体,我们希望将其在量筒中混合成出比例为$x:y$的液体,我们只有两种操作,将量筒用一种液体填满,或者将量筒中的液体倒出直到剩余液体只剩$a$为止,问是否可能混合出目标液体,如果可以,至少需要多少次操作。
 
数据范围:组数$1\le{T}\le{1e5}$, $1\le{a,b,x,y}\le{1e18}$
 
思路:令$c=a+b$,考虑每次倒水操作后的比例:
$1\rightarrow$$\frac{c}{c}:0$, $0:\frac{c}{c}$
$2\rightarrow$$\frac{a}{c}:\frac{b}{c}$, $\frac{b}{c}:\frac{a}{c}$
$3\rightarrow$$\frac{a^2+bc}{c^2}:\frac{ab}{c^2}$, $\frac{a^2}{c^2}:\frac{ab+bc}{c^2}$, $\frac{ab}{c^2}:\frac{a^2+bc}{c^2}$, $\frac{ab+bc}{c^2}:\frac{a^2}{c^2}$
$4\rightarrow$$\frac{a^3+abc+bc^2}{c^3}:\frac{a^2b}{c^3}$, $\frac{a^3+abc}{c^3}:\frac{a^2b+bc^2}{c^3}$, $\frac{a^3+bc^2}{c^3}:\frac{a^2b+abc}{c^3}$, $\frac{a^3}{c^3}:\frac{a^2b+abc+bc^2}{c^3}$...
换句话说,对于第i次倒水操作$(i>1)$,其对于第n次倒水操作后情况的比例为$\frac{b}{c}(\frac{a}{c})^{n-i}$,上式的分子之和为$a^{n-1}+\sum_{i-1}^{n-1}(ba^{n-i}c^{i-1})$,分母为$c^{n-1}$。故对于$x+y=c^{n-1}$时,令$A={\left\{a^{n-1},ba^{n-2}c^{0},ba^{n-3}c^{1}...,ba^{0}c^{n-2}\right\}}$,若有$B\subset{A}$,且  $x=\sum{B}$,$y=\sum{\complement_{A}{B}}$,则有解且最小次数为$n$。接着逐项考虑每次的倒水操作倒的是什么,我们逐项考虑是否存在,若 $c | {\frac{\sum{A-\left\{a^{n}\right\}}}{b}}$,由$a,c$互质可知项$a^{n−2}c^{0}$不存在,接着递归考虑去除该项后集合的情况。
#include <bits/stdc++.h>
#define ft first
#define sd second
#define pb push_back
#define MP make_pair
#define ll long long
#define ld long double
#define pll pair<ll,ll>
#define lowbit(a) ((a)&-(a))
#define ull unsigned long long
#define all(x) x.begin(),x.end()
#define nps fixed<<setprecision(10)<<
#define mem(a,k) memset(a,k,sizeof(a))
#define debug(x) cout<<#x<<"="<<x<<endl
#define rep(i,a,b) for(ll i=(a);i<=(b);i++)
#define per(i,a,b) for(ll i=(a);i>=(b);i--)
const ll N=1e6+10;
const ll mod1=1e9+7;
const ll mod2=998244353;
using namespace std;
ll t,n,m,k,tt,tp,sum,ans,res,cnt;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr),cout.tie(nullptr);
    //IO
    cin>>t;
    while(t--)
    {
        ll x,y,a,b;
        cin>>x>>y>>a>>b;
        ll kk=__gcd(a,b);
        a/=kk,b/=kk;
        ans=cnt=0;
        while(1)
        {
            ll kk=__gcd(x,y);
            x/=kk,y/=kk;
            if(x+y==a+b)
            {
                if((x==a&&y==b)||(x==b&&y==a))ans=cnt+2;
                else ans=-1;
                break;
            }
            ++cnt;
            if((x+y)%(a+b))
            {
                ans=-1;
                break;
            }
            if(y%a==0&&(x+y)/(a+b)*b<x)x-=(x+y)/(a+b)*b;
            else if(x%a==0&&(x+y)/(a+b)*b<y)y-=(x+y)/(a+b)*b;
            else
            {
                ans=-1;
                break;
            }
        }
        cout<<ans<<'\n';
    }
}
/*






*/
View Code

 

Problem D. Transition
Problem E. Multigate
Problem F. Angel
题意:一条直线上有$n$个洞,一只兔子在其中一个洞中,每个时刻它都会移动到相邻的一个洞中,每个时刻你都可以在它移动之前选择任意一个洞尝试抓住它,问是否有策略保证能抓到兔子,如有,那么至少需要几次。
 
数据范围:$1\le{n}\le{1e3}$
 
思路:考虑第一次选择点时,实际上是把兔子可能存在的位置切分成两部分,考虑朝固定方向将可能存在的左区间或右区间夹断,利用兔子在两侧时只能朝固定方向移动的性质使得兔子可能存在的点只能在一侧,随后用相同的方法反向把可能的位置夹断,注意特判$n<3$时的情况。
#include <bits/stdc++.h>
#define ft first
#define sd second
#define pb push_back
#define MP make_pair
#define ll long long
#define ld long double
#define pll pair<ll,ll>
#define lowbit(a) ((a)&-(a))
#define ull unsigned long long
#define all(x) x.begin(),x.end()
#define nps fixed<<setprecision(10)<<
#define mem(a,k) memset(a,k,sizeof(a))
#define debug(x) cout<<#x<<"="<<x<<endl
#define rep(i,a,b) for(ll i=(a);i<=(b);i++)
#define per(i,a,b) for(ll i=(a);i>=(b);i--)
const ll N=1e6+10;
const ll mod1=1e9+7;
const ll mod2=998244353;
using namespace std;
ll t,n,m,k,tt,tp,sum,ans,res,cnt;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr),cout.tie(nullptr);
    //IO
    //cin>>t;
    //while(t--)
    {
        cin>>n;
        if(n==1)cout<<"1\n1";
        else if(n==2)cout<<"2\n1 1";
        else
        {
            cout<<2*(n-2)<<'\n';
            rep(i,2,n-1)cout<<i<<" ";
            per(i,n-1,2)cout<<i<<" ";
        }
        cout<<'\n';
    }
}
/*








*/
View Code

 

Problem G. Brick
Problem H. Hamster and Multiplication
Problem I. Latitude Compressor
Problem J. Palindrome Reversion
题意:给定一个字符串,问能否选择一个子字符串翻转使得字符串变为回文串,如能,输出任意一个子串的位置。
 
数据范围:$|S|\le{1e5}$
 
思路:首先不难发现如果翻转$[1-i]$合法且$S$中有相同长度$LEN$的前缀和后缀为回文时也存在解$[Len+1,i]$,故优先考虑删除互为回文的前缀后缀,剩下的情况首先判断本身为回文串的情况,然后考虑翻转区间的左值为余下字符串最左侧和右值为余下字符串最右侧时的情况,只有在这两种情况下才把余下串变为串1-回文串-串1的回文形式。
#include <bits/stdc++.h>
#define ft first
#define sd second
#define pb push_back
#define MP make_pair
#define ll long long
#define ld long double
#define pll pair<ll,ll>
#define lowbit(a) ((a)&-(a))
#define ull unsigned long long
#define all(x) x.begin(),x.end()
#define nps fixed<<setprecision(10)<<
#define mem(a,k) memset(a,k,sizeof(a))
#define debug(x) cout<<#x<<"="<<x<<endl
#define rep(i,a,b) for(ll i=(a);i<=(b);i++)
#define per(i,a,b) for(ll i=(a);i>=(b);i--)
const ll N=1e6+10;
const ll mod1=1e9+7;
const ll mod2=998244353;
const ll base1=1610612741;
using namespace std;
ll t,n,m,k,tt,tp,sum,ans,res,cnt;
const ll P=133331;
ll hsh1[N],hsh2[N],hsh3[N],hsh4[N],p[N];
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr),cout.tie(nullptr);
    //IO
    string s;
    cin>>s;
    n=s.size();
    s=" "+s;
    ll l=1,r=n;
    while(s[l]==s[r])
    {
        ++l;
        --r;
        if(l>=r)break;
    }
    ll res=1;
    rep(i,l,r)hsh1[i]=((hsh1[i-1]*P)%base1+s[i])%base1;
    rep(i,l,r)
    {
        hsh2[i]=(hsh2[i-1]+(s[i]*res)%base1)%base1;
        res=(res*P)%base1;
        p[i-l+1]=res;
    }
    res=1;
    per(i,r,l)
    {
        hsh3[i]=(hsh3[i+1]+(s[i]*res)%base1)%base1;
        res=(res*P)%base1;
    }
    per(i,r,l)hsh4[i]=((hsh4[i+1])*P%base1+s[i])%base1;
    rep(i,l,r)
    {
        if(((hsh2[i]*p[r-i])%base1+hsh3[i+1])%base1==((hsh4[i+1]*p[i-l+1]%base1)+hsh1[i])%base1)
        {
            cout<<l<<" "<<i;
            return 0;
        }
        if(((hsh1[i-1]*p[r-i+1])%base1+hsh4[i])%base1==((hsh3[i]*p[i-l])%base1+hsh2[i-1])%base1)
        {
            cout<<i<<" "<<r;
            return 0;
        }
    }
    if(l>=r)cout<<"1 1";
    else cout<<"-1 -1";
}
/*
aaaab







*/
View Code

 

Problem K. PTT
 签到,注意答案非负。
#include <bits/stdc++.h>
#define ft first
#define sd second
#define pb push_back
#define MP make_pair
#define ll long long
#define ld long double
#define pll pair<ll,ll>
#define lowbit(a) ((a)&-(a))
#define ull unsigned long long
#define all(x) x.begin(),x.end()
#define nps fixed<<setprecision(10)<<
#define mem(a,k) memset(a,k,sizeof(a))
#define debug(x) cout<<#x<<"="<<x<<endl
#define rep(i,a,b) for(ll i=(a);i<=(b);i++)
#define per(i,a,b) for(ll i=(a);i>=(b);i--)
const ll N=1e6+10;
const ll mod1=1e9+7;
const ll mod2=998244353;
using namespace std;
ll t,n,m,k,tt,tp,sum,ans,res,cnt;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr),cout.tie(nullptr);
    //IO
    cin>>t;
    while(t--)
    {
        cin>>n;
        double c;
        cin>>c;
        if(n>=10000000)c+=2.0;
        else if(n>=9800000)c+=1.0+((double)n-9800000)/200000;
        else c+=((double)n-9500000)/300000;
        c=max(0.0,c);
        cout<<nps c<<'\n';
    }
}
/*



*/
View Code

 

Problem L. Chtholly and the Broken Chronograph
 题意:给定一个数组,每个数处于开启或关闭状态,要求进行单点状态变换,区间开启点的加法和区间和查询操作。
 
数据范围:$1\le{n,q}\le{1e5}$, $1\le{a_i}\le{1e8}$
 
思路:线段树基操。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<double, double> pdd;
#define fast ios::sync_with_stdio(false),cin.tie(0)
#define pi acos(-1)
#define lowbit(a) (a&(-a))
#define endl  '\n'
#define mem(a,b) memset(a,b,sizeof(a))
constexpr auto eps = 1e-12;
constexpr ll inf = 0x7fffffffffffffff;
constexpr ll mod = 1e9 + 7;
constexpr ll mod1 = 998244353;
ll gcd(ll a, ll b) { return b > 0 ? gcd(b, a % b) : a; }
ll qpow(ll a, ll n, ll p) { ll ans = 1; while (n) { if (n & 1)ans = ans * a % p; n >>= 1; a = a * a % p; }return ans; }
ll qpow(ll a, ll n) { ll ans = 1; while (n) { if (n & 1)ans = ans * a; n >>= 1; a = a * a; }return ans; }
double qpow(double a, ll n) { double ans = 1; while (n) { if (n & 1)ans = ans * a; n >>= 1; a = a * a; }return ans; }
class pcmp { public:bool operator()(const pair<ll, ll>& a, const pair<ll, ll>& b) const { return a.first == b.first ? (a.second < b.second) : (a.first < b.first); } };
//inline ll read() { char ch = getchar(); ll x = 0, f = 1; while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); } while ('0' <= ch && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; }
//mt19937 rnd(time(0));
//ifstream h;h.open("D:\\123.txt", ios::in)
const int N = 1e5 + 5;
struct s
{
    ll sum = 0, add = 0, l, r, suma = 0;
};
int a[N], b[N];
s tr[N << 2];
void build(int pos, int l, int r)
{
    tr[pos].l = l, tr[pos].r = r;
    if (l == r)
    {
        tr[pos].sum = a[l];
        tr[pos].suma = b[l];
        return;
    }
    int mid = (l + r) >> 1;
    build(pos << 1, l, mid);
    build(pos << 1 | 1, mid + 1, r);
    tr[pos].sum = (tr[pos << 1].sum + tr[pos << 1 | 1].sum);
    tr[pos].suma = (tr[pos << 1].suma + tr[pos << 1 | 1].suma);
}
void pd(int pos)
{
    int ls = pos << 1, rs = pos << 1 | 1;
    tr[ls].sum += tr[pos].add * tr[ls].suma;
    tr[rs].sum += tr[pos].add * tr[rs].suma;

    tr[ls].add += tr[pos].add;
    tr[rs].add += tr[pos].add;

    tr[pos].add = 0;
}
void change(int pos, int x, int y)
{
    if (x == tr[pos].l && tr[pos].r == x)
    {
        tr[pos].suma = y;
        return;
    }
    pd(pos);
    int mid = (tr[pos].l + tr[pos].r) >> 1;
    if (x <= mid)
        change(pos << 1, x, y);
    if (x > mid)
        change(pos << 1 | 1, x, y);
    tr[pos].sum = (tr[pos << 1].sum + tr[pos << 1 | 1].sum);
    tr[pos].suma = (tr[pos << 1].suma + tr[pos << 1 | 1].suma);
}
void upadd(int pos, int x, int y, int k)
{
    if (x <= tr[pos].l && tr[pos].r <= y)
    {
        tr[pos].sum = (tr[pos].sum + k * tr[pos].suma);
        tr[pos].add = (tr[pos].add + k);
        return;
    }
    pd(pos);
    int mid = (tr[pos].l + tr[pos].r) >> 1;
    if (x <= mid)
        upadd(pos << 1, x, y, k);
    if (y > mid)
        upadd(pos << 1 | 1, x, y, k);
    tr[pos].sum = (tr[pos << 1].sum + tr[pos << 1 | 1].sum);
    tr[pos].suma = (tr[pos << 1].suma + tr[pos << 1 | 1].suma);
}
ll query(int pos, int x, int y)
{
    ll ans = 0;
    if (x <= tr[pos].l && tr[pos].r <= y)
        return tr[pos].sum;
    pd(pos);
    int mid = (tr[pos].l + tr[pos].r) >> 1;
    if (x <= mid)
        ans = (ans + query(pos << 1, x, y));
    if (y > mid)
        ans = (ans + query(pos << 1 | 1, x, y));
    return ans;
}
int main()
{
    fast;
    int T = 1;
    //cin >> T;
    while (T--)
    {
        ll n, q;
        cin >> n >> q;
        for (int i = 1; i <= n; i++)
            cin >> a[i];
        for (int i = 1; i <= n; i++)
            cin >> b[i];
        build(1, 1, n);
        while (q--)
        {
            ll op, x = 0;
            cin >> op;
            if (op == 1)
                cin >> x, b[x] = 0, change(1, x, 0);
            else if (op == 2)
                cin >> x, b[x] = 1, change(1, x, 1);
            else if (op == 3)
            {
                ll l, r;
                cin >> l >> r >> x;
                upadd(1, l, r, x);
            }
            else if (op == 4)
            {
                ll l, r;
                cin >> l >> r;
                cout << query(1, l, r) << endl;
            }
        }
    }
}
/*
4 2 5 3
1 0 0 1

4 2 5 3
1 0 1 1

5 2 6 4
1 0 0 1 --->17

5 2 6 4
0 0 0 1
0 1 0 1

5 4 6 4 --->19

*/
View Code

 

Problem M. Super Star Spectacle
posted @ 2022-07-06 11:21  Geospiza  阅读(465)  评论(0)    收藏  举报