AIsing Programming Contest 2020 总结

A - Number of Multiples

按照题目意思走就行

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#include<iostream>
#include<algorithm>
using namespace std;
int l,r,d;
int main()
{
    IO;
    cin>>l>>r>>d;
    if(r<l) swap(l,r);
    int res=r/d-l/d;
    if(l%d==0) res++;
    cout<<res<<endl;
    return 0;
}

B - An Odd Problem

这题比A还纯模拟,按题目意思走

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#include<iostream>
#include<algorithm>
using namespace std;
const int N=110;
int a[N],n;
int main()
{
    IO;
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    int res=0;
    for(int i=1;i<=n;i++)
        if((i&1)&&(a[i]&1)) res++;
    cout<<res<<endl;
    return 0;
}

C - XYZ Triplets

这题刚开始看错数据范围,结果RE了,然后又算错时间复杂度又TLE了,我也太菜了吧

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int N=10010;
const double eps=1e-6;
int n,f[N];
double calc1(int x,int y,int n)
{
    double delta=(x+y)*(x+y)-4*(x*x+y*y+x*y-n);
    if((x+y)*(x+y)<=4*(x*x+y*y+x*y-n)) return -1;
    return (sqrt(delta)-(x+y))/2.0;
}
int calc2(int x,int y,int n)
{
    int delta=(x+y)*(x+y)-4*(x*x+y*y+x*y-n);
    if(delta<=0) return -2;
    return (sqrt(delta)-(x+y))/2;
}
int main()
{
    IO;
    cin>>n;
    for(int k=1;k<=n;k++)
        for(int i=1;i<=k/i;i++)
            for(int j=1;j<=k/j;j++)
            {
                double x=calc1(i,j,k);
                int y=calc2(i,j,k);
                if(x<eps) continue;
                if(abs(x-y)<eps) f[k]++;
            }
    for(int i=1;i<=n;i++) cout<<f[i]<<endl;
    return 0;
}

又是只做了三题,真就是签到战士?

D - Anything Goes to Zero

这题考试时想要高精度,我发现要写好几个高精度就懒得看了。第二天一看发现快速幂取模可以避免高精度,然后在网上搜了搜题解,搞了一上午终于AC了。
对于原二进制串中1的个数可能又三种情况①大于1②等于1③等于0我们可以发现只要模第一次,那么这个数就会回到 i n t int 范围内,不妨设原二进制串中 1 1 的个数为 s s ,那么,第一次的需要模的数只有两种情况 s 1 , s + 1 s-1,s+1 ,于是我们可以用快速幂预处理出原串模 s 1 , s + 1 s-1,s+1 的值,每当反转一位就相当于加上或减去2的整次幂,然后就可以很容易知道答案。
对于①存在 s 1 , s + 1 s-1,s+1 ,而对于②只存在模 s + 1 s+1 的情况:如果模 0 0 那么说明该串全是0,那么答案自然直接是 0 0 ,如果模 s + 1 s+1 ,那么肯定模的是 2 2 ,如果最后一位不是 1 1 该串是偶数,操作一次就可以了,如果最后一位是 1 1 ,那么该串是奇数,稍微那么该操作需要两次。对于③也是只存在模 s + 1 s+1 的情况,而且肯定是模 1 1 ,分析可知只用操作一次就可。

#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=200010;
int a[N],n;
ll qmi(ll a,ll b,ll p)
{
    ll res=1%p;
    a%=p;
    while(b)
    {
        if(b&1) res=res*a%p;
        b>>=1;
        a=a*a%p;
    }
    return res;
}
int calc(ll x)//计算二进制中1的个数
{
    int res=0;
    while(x)
    {
        x-=x&-x;
        res++;
    }
    return res;
}
ll md(ll x,ll y)//取模函数,保证取模后是正数
{
    return (x%y+y)%y;
}
int main()
{
    cin>>n;
    int s=0;
    for(int i=1;i<=n;i++)
    {
        scanf("%1d",&a[i]);
        s+=a[i];
    }
    if(s>1)
    {
        ll x=0,y=0;
        for(int i=1;i<=n;i++)
        {
            if(a[i]==0) continue;
            x=md(x+qmi(2,n-i,s-1),s-1);//预处理原串模s-1和s+1的值
            y=md(y+qmi(2,n-i,s+1),s+1);
        }
        for(int i=1;i<=n;i++)
        {
            ll ans=0;
            int cnt=1;
            if(a[i]==0) ans=md(y+qmi(2,n-i,s+1),s+1);
            else ans=md(x-qmi(2,n-i,s-1),s-1);
            while(ans)
            {
                ans%=calc(ans);
                cnt++;
            }
            cout<<cnt<<endl;

        }
    }
    else if(s==0) 
        for(int i=1;i<=n;i++) cout<<1<<endl;
    else
    {
        for(int i=1;i<=n;i++)
        {
            if(a[i]==1) cout<<0<<endl;//该串唯一的一个1被反转,串值变成0
            else
            {
                if(a[n]==1||i==n) cout<<2<<endl;//最后一位是1
				else cout<<1<<endl;
            }
        }
    }
    return 0;
}

E - Camel Train

①贪心+小根堆

题中有两种骆驼一种 l > = r l>=r ,那么该骆驼需要尽可能往前放,另一种骆驼 l < r l<r 尽可能往后放,并且它们的最优解互不影响。因此我们可以分别考虑两种骆驼,不管哪种骆驼我们先把答案加上小的数,然后就变成之前做过的一个题lyd老师的<<算法竞赛进阶指南>>中的超市那道题。
贪心:按照位置贪心

#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
#define k first
#define w second
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N=200010;
pii a[N],b[N];
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        int n,cnta=0,cntb=0;
        cin>>n;
        ll res=0;
        for(int i=0;i<n;i++)
        {
            int k,l,r;
            cin>>k>>l>>r;
            if((k==0&&l>=r)||(k==n&&r>l)) 
            {
                res+=min(l,r);
                continue;
            }
            if(l>=r) res+=r,a[cnta++]={k,l-r};
            else res+=l,b[cntb++]={n-k,r-l};
        }
        sort(a,a+cnta),sort(b,b+cntb);
        priority_queue<int,vector<int>,greater<int> >heap;
        for(int i=0;i<cnta;i++)
        {
            heap.push(a[i].w);
            while(heap.size()>a[i].k) heap.pop();
        }
        while(heap.size())
        {
            res+=heap.top();
            heap.pop();
        }
        for(int i=0;i<cntb;i++)
        {
            heap.push(b[i].w);
            while(heap.size()>b[i].k) heap.pop();
        }
        while(heap.size())
        {
            res+=heap.top();
            heap.pop();
        }
        cout<<res<<endl;
    }
    return 0;
}
②贪心+并查集

贪心:按照权值从大到小排序,对于每个牛,排到恰好的位置上,如果恰好的位置上有牛,就往前找看看前面有没有空位置。并查集维护1~pospos最近并且位置为空的序号

#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
#define w first
#define k second
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N=200010;
pii a[N],b[N];
int p[N];
int find(int x)
{
    if(p[x]!=x) p[x]=find(p[x]);
    return p[x];
}
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        int n,cnta=0,cntb=0;
        cin>>n;
        ll res=0;
        for(int i=1;i<=n;i++) p[i]=i;
        for(int i=0;i<n;i++)
        {
            int k,l,r;
            cin>>k>>l>>r;
            if((k==0&&l>=r)||(k==n&&r>l)) 
            {
                res+=min(l,r);
                continue;
            }
            if(l>=r) res+=r,a[cnta++]={l-r,k};
            else res+=l,b[cntb++]={r-l,n-k};
        }
        sort(a,a+cnta),sort(b,b+cntb);
        reverse(a,a+cnta),reverse(b,b+cntb);
        for(int i=0;i<cnta;i++)
        {
            int pos=find(a[i].k);
            if(pos) p[pos]=pos-1,res+=a[i].w;
        }
        for(int i=1;i<=n;i++) p[i]=i;
        for(int i=0;i<cntb;i++)
        {
            int pos=find(b[i].k);
            if(pos) p[pos]=pos-1,res+=b[i].w;
        }
        cout<<res<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Fighting_Peter/article/details/107314818