• HPU personal training


    A - Engines Atcoder 4900

    题目大意:n个点,任意几个点组合后得到的点距离原点的最远距离。

    题解:极角排序:https://blog.csdn.net/qq_39942341/article/details/79840394

    利用极角排序,将这些点看成与原点相作用的向量,然后根据平行四边行法则,两向量之间的角度相差越小,其复合得到的向量的长度越长

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1E5+7;
    struct stu{
        double a,b;
        bool friend operator <(const stu &x,const stu &y){
            return atan2(x.b,x.a)<atan2(y.b,y.a);
        }
    }arr[N];
    int nxt[N];
    int main(){
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)    cin>>arr[i].a>>arr[i].b;    
        for(int i=1;i<=n;i++) nxt[i]=i+1;
        nxt[n]=1;
        sort(arr+1,arr+1+n);
        double ans=0;
        for(int i=1;i<=n;i++){//以每个点为起始点,遍历一圈后回到起始点,同时记录大小 
            double dx=arr[i].a;
            double dy=arr[i].b;
            ans=max(ans,arr[i].a*arr[i].a+arr[i].b*arr[i].b);
            
            for(int j=nxt[i];j!=i;j=nxt[j]){
                dx+=arr[j].a;
                dy+=arr[j].b;
                ans=max(ans,dx*dx+dy*dy);
            }
        }
        printf("%.15lf
    ",sqrt(ans));
        return 0;
    }

    B - Consecutive Integers

    规律

    #include<iostream>
    using namespace std;
    int main(){
        int n,k;
        cin>>n>>k;
        cout<<n-k+1<<endl;
        return 0;
    }

    C - ModSum

    规律题。错一位取余相加

    #include<iostream>
    using namespace std;
    typedef long long ll;
    int main()
    {
        ll n;
        cin>>n;
        cout<<n*(n-1)/(ll)2<<endl;    
        return 0;
    }

    D - Shortest Path on a Line

     题目大意:输入一个范围。从L[i]~R[i],在这个范围内的两个数(s<t)s到t的权值为C,求点1到点N的最短距离

    题解:从i到i-1建一个权值为0的反向边,这样就能使得一个范围L[i]~R[i]任意两点之间的距离为C。不足之处,仅限与求从S到T(S<T)的情况。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const ll INF=1E18+7;
    const ll N=1E5+7;
    ll n,m;
    struct stu{
        ll a,b;
        bool friend operator <(const stu &x,const stu &y){
            return x.b>y.b;
        }
    };
    vector <stu >ve[N];
    bool mark[N];
    ll dp[N];
    void djstrea(){
        priority_queue<stu>que;
        que.push({1,0});
        dp[1]=0;
        while(que.size()){
            stu x=que.top();
            que.pop();
            if(mark[x.a]) continue ;
            mark[x.a]=1;
            for(ll i=0;i<ve[x.a].size();i++){
                ll dx=ve[x.a][i].a;
                ll dy=ve[x.a][i].b;
                if(dp[dx]>dp[x.a]+dy){
                    dp[dx]=dp[x.a]+dy;
                    que.push({dx,dp[dx]});
                }
            }
        }
    }
    int main(){
        cin>>n>>m;
        ll x,y,z;
        for(ll i=1;i<=n;i++) {
            ve[i].push_back({i-1,0});
        }
        for(ll i=0;i<=n;i++) dp[i]=INF;
        for(ll i=1;i<=m;i++){
            cin>>x>>y>>z;
            ve[x].push_back({y,z});
        }
        djstrea();
        if(dp[n]==INF)   cout<<-1<<endl;
        else cout<<dp[n]<<endl;
        return 0;
    }

    E - Counting of Trees

     思维

    注意1为根节点,D[i]指的是1到i的距离。所以这里0的个数必须为1,而且只能是d[1]=0,其他的地方不能出现0。然后我们在找到最大的权值,权值为i的点只能连接在权值为i-1上,因此共有arr[i-1]^arr[i]种可能;

    #include<iostream>
    #include<cstdio>
    using namespace std;
    typedef long long ll;
    
    const int N=1e5+7;
    const ll mod=998244353;
    
    ll arr[N];
    ll ksm(ll x,ll y){
        ll res=1;
        while(y){
            if(y&1) res=res*x%mod;
            x=x*x%mod;
            y>>=1;
        }
        return res%mod;
    }
    
    int main()
    {
        ll n;
        cin>>n;
        ll x;
        ll sum=1;
        ll s=0;
        for(ll i=1;i<=n;i++){
            cin>>x;
            if(i==1&&x!=0) sum=0;
            arr[x]++;
            s=max(x,s);
        }
        for(ll i=s;i>=0;i--){
            if(arr[i]==0) sum=0;
            if(i>1){
                sum=sum*ksm(arr[i-1],arr[i])%mod;
            }
        }
        if(arr[0]>1) sum=0;
        cout<<sum%mod<<endl;
        return 0;
     } 

    F - Monsters Battle Royale

    模拟一下过程,始终的大的减去小的。所以答案应该为这些数的__gcd

    #include<bits/stdc++.h>
    using namespace std;
    
    
    int main()
    {
        int n;
        cin>>n;
        int g;
        for(int i=1;i<=n;i++) {
            int x;
            cin>>x;
            if(i==1){
                g=x;
            }
            else {
                g=__gcd(g,x);
            }
        }
        cout<<g<<endl;
        return 0;
    }

    G - Powerful Discount Tickets

     把所有的票都用完,并且每次都要给最贵的用,所有用优先队列

    #include<iostream>
    #include<queue>
    #include<cstdio>
    using namespace std;
    typedef long long ll;
    priority_queue<ll >que;
    int main()
    {
        ll n,m;
        cin>>n>>m;
        ll x;
        for(ll i=1;i<=n;i++){
            cin>>x;
            que.push(x);
        }
        ll ans=0;
        while(m--){
            ll x=que.top();
            que.pop();
            x=x/2;
            que.push(x);
        }
        while(que.size()){
            ans+=que.top();
            que.pop();
        }
        cout<<ans<<endl;
        return 0;
    }

    H - Attack Survival

     模拟一下就好了

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1E5+7;
    int arr[N];
    int main(){
        int n,k,q;
        cin>>n>>k>>q;
        for(int i=1;i<=q;i++){
            int x;    
            cin>>x;
            arr[x]++;
        }
        for(int i=1;i<=n;i++){
            int a=k-(q-arr[i]);
            if(a<=0) cout<<"No"<<endl;
            else cout<<"Yes"<<endl;
        }
        return 0;
    }

    I - Lower

     模拟

    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int N=1E5+7;
    int arr[N];
    int main()
    {
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)    cin>>arr[i];
        int ans=0;
        int sum=0;
        for(int i=n-1;i>=1;i--){
            if(arr[i]>=arr[i+1]) ans++;
            else ans=0;
            sum=max(ans,sum);
        }
        cout<<sum<<endl;
        return 0;
    }

    J - Kleene Inversion

     求一下单个区间内的逆序对的个数x,在求两个复合区间的逆序对的个数y,然后x*k+y*(k-1)*k/2,,取余的时候要注意,会爆longlong。

    求逆序对用到了归并排序

    #include<bits/stdc++.h> 
    using namespace std;
    const int N=5e5+7;
    typedef long long ll;
    const ll mod=1e9+7;
    ll arr[N];
    ll mark[N];
    ll right_[N];
    ll ans=0;
    void merage_sort(ll l,ll r){
        if(l>=r) return ;
        ll mid=(l+r)/2;
        merage_sort(l,mid);
        merage_sort(mid+1,r);
        ll i=l,j=mid+1,k=l;
        while(i<=mid&&j<=r){
            if(arr[i]<=arr[j]){
                right_[k++]=arr[i++];
            }
            else {
                right_[k++]=arr[j++];
                ans+=1ll*mid-i+1;
            }
        }
        while(i<=mid)    right_[k++]=arr[i++];
        while(j<=r)   right_[k++]=arr[j++];    
        for(ll i=l;i<=r;i++)    arr[i]=right_[i];
    }
    int main(){
        ll n,k;
        cin>>n>>k;
        for(ll i=1;i<=n;i++){
            cin>>arr[i];
            mark[i]=arr[i];
        }
        ll ans1;
        merage_sort(1,n);
        ans1=ans;
        ll ans2=0;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                if(arr[i]>arr[j]) ans2++;
            }
        }
        cout<<(k%mod*ans1%mod+k%mod*(k-1)/2%mod*ans2%mod)%mod<<endl;
        return 0;
    }

    K - Two Contests

     

    题目连接:https://atcoder.jp/contests/agc040/tasks/agc040_b

    大佬题解:https://blog.csdn.net/duanghaha/article/details/102892233 

    题意:有N个问题,每个问题可以由编号L~R之间的人完成,有两个集合S和T,将N个问题放入两个集合中,使得交集和最大

    题解与证明

    首先找到lmost,与rmin,当区间rmin与lmost在同一个集合中,此时答案为rmin-lmost+1+most_width(最大宽度)

    当二者不再同一个集合中时,那么答案为  max((rmin-x+1)+(y-lmost+1))其中x为l[i],y为r[j]注意x与y不可以是同一个区间的左右边界。

    现在已经确定了集合S中有lmost,所以,T中一定有rmin。。问题转换为一个数组,,两个参数,将这个数组划分为来年部分。使得两部分的和最大

    #include<bits/stdc++.h>
    using namespace std;
    const int INF=1e9+7;
    const int N=1E5+7;
    int l[N],r[N];
    int arr[N];
    struct stu{
        int a,b;
        bool friend operator <(const stu &x,const stu &y){
            return x.a>y.a;
        }
    }s[N];
    int main()
    {
        int n;
        cin>>n;
        int lmax=0,rmin=INF,width=0;
        for(int i=1;i<=n;i++){
            cin>>l[i]>>r[i];
            if(l[i]>=lmax)    lmax=l[i];
            if(r[i]<=rmin)    rmin=r[i];
            width=max(width,r[i]-l[i]+1);
        }
        int sum=max(rmin-lmax+1,0)+width;
        for(int i=1;i<=n;i++){
            s[i].a=max(0,rmin-l[i]+1);
            s[i].b=max(0,r[i]-lmax+1);
        }
        sort(s+1,s+1+n); 
        arr[n]=s[n].b;
        for(int i=n-1;i>=1;i--)    arr[i]=min(arr[i+1],s[i].b);
        int ans=0;
        for(int i=1;i<=n-1;i++)    ans=max(ans,s[i].a+arr[i+1]);
        cout<<max(ans,sum)<<endl;
        return 0;
     }

    M - AB Substrings

     记录一下以b开头的字符串的数目,记录一下以a结尾的字符串的数目,在记录以b开头a结尾的字符串的数目

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    ll aend=0,bhead=0,ab=0;
    int main()
    {
        int n;
        cin>>n;
        string s;
        ll ans=0;
        for(int i=1;i<=n;i++){
            cin>>s;
            int x=s.size();
            for(int j=0;j<x-1;j++){
                if(s[j]=='A'&&s[j+1]=='B')    ans++;
            }
            if(s[0]=='B'&&s[x-1]=='A') ab++;    
            if(s[0]=='B') bhead++;
            if(s[x-1]=='A') aend++;
        }
        aend-=ab;
        bhead-=ab;
        if(aend==0&&bhead==0){
            if(ab==0||ab==1) cout<<ans<<endl;
            else cout<<ans+ab-1<<endl;
        }
        else if(aend==0||bhead==0){
            cout<<ans+ab<<endl;
        }
        else if(aend!=0&&bhead!=0){
            cout<<ans+min(aend,bhead)+ab<<endl;
        }
        return 0;
    }
  • 相关阅读:
    three.js详解
    Javascript的原型
    Transform? Transition? Animation?
    Backbone源码分析Backbone架构+流程图
    对象是引用的注意原型中的属性改变
    MySQL+ JSP+Tomcat開發指引
    MySQL應用分析
    SQL 日期
    MySQL安裝
    MSE错误应对分享
  • 原文地址:https://www.cnblogs.com/Accepting/p/11913932.html
Copyright © 2020-2023  润新知