hdu多校第一场题解(>=100人)

版权声明:转载之前请说你是博主的粉丝哦。 https://blog.csdn.net/qq_34921856/article/details/81989507

B - Balanced Sequence
预处理出每个串未匹配的)及(的个数,看这个范围大致可以猜出是贪心。然而博主单纯的按照(从大到小排序。。看了题解才发现还能这样。。
这题主要的trick是排序方式,记好了!

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
struct node
{
    int L,R;
    int idx;
    node(int L,int R,int idx):L(L),R(R),idx(idx){}
    node(){}
}t[maxn];
char s[maxn];
long long sum;
void solve(int idx)
{
    int l=0,r=0;
    int num=0;
    int len=strlen(s);
    for(int i=0;i<len;i++)
    {
        if(s[i]=='(')
        {
            num++;
        }
        else
        {
            if(num==0)
            {
                r++;
            }
            else
            {
                num--;
                sum+=2;
            }
        }
    }
    l=num;
    t[idx].L=l,t[idx].R=r,t[idx].idx=idx;
}
bool cmpl(const node &a,const node &b)
{
    if(a.L<a.R&&b.L>b.R)
        return false;
    else if(a.L<a.R&&b.L<b.R)
        return a.L>b.L;
    else if(a.L>=a.R&&b.L<b.R)return 1;
    else return a.R<b.R;
}
long long dp[maxn];
long long suml[maxn];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        sum=0;
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%s",s);
            solve(i);
        }
        sort(t+1,t+1+n,cmpl);
        for(int i=1;i<=n;i++)
        {
            long long r=t[i].R;
            long long tmp=min(r,suml[i-1]-dp[i-1]);
            dp[i]=dp[i-1]+tmp;
            suml[i]=suml[i-1]+t[i].L;
        }
        sum+=2LL*dp[n];
        printf("%lld\n",sum);
    }
    return 0;
}

D - Distinct Values
这题还是挺好做的,排个序之后从左到右依次处理每个区间,再开个数组看当前区间那些数被用了。实际上这个做法比较像莫队的转移。。

#include<bits/stdc++.h>
using namespace std;
const int maxm=1e5+5;
const int maxn=1e5+5;
typedef pair<int,int>pii;
pii facts[maxm];
int num[maxn];
int ans[maxn];

bool cmp(pii a,pii b)
{
    if(a.first!=b.first)
        return a.first<b.first;
    return a.second>b.second;
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset(num,0,sizeof(num));
        memset(ans,-1,sizeof(ans));
        int n,m;
        scanf("%d %d",&n,&m);
        int l,r;
        for(int i=1;i<=m;i++)
        {
            scanf("%d %d",&l,&r);
            facts[i]=make_pair(l,r);
        }
        sort(facts+1,facts+1+m,cmp);
        for(int i=1;i<=facts[1].first;i++)
            ans[i]=1;
        for(int i=facts[1].first;i<=facts[1].second;i++)
            ans[i]=i-facts[1].first+1,num[i-facts[1].first+1]=1;
        int lnode=facts[1].first,rnode=facts[1].second;
        for(int i=2;i<=m;i++)
        {
            if(facts[i].second<=rnode)continue;
            if(facts[i].first>rnode)
            {
                memset(num,0,sizeof(num));
                for(int j=rnode+1;j<=facts[i].first;j++)
                    ans[j]=1;
                for(int j=facts[i].first;j<=facts[i].second;j++)
                {
                    ans[j]=j-facts[i].first+1;
                    num[j-facts[i].first+1]=1;
                }
                lnode=facts[i].first,rnode=facts[i].second;
            }
            else
            {
                for(int j=lnode;j<facts[i].first;j++)
                {
                    num[ans[j]]=0;
                }
                int now=1;
                for(int j=rnode+1;j<=facts[i].second;j++)
                {
                    while(num[now])now++;
                    ans[j]=now;
                    num[now++]=1;
                }
                lnode=facts[i].first;
                rnode=facts[i].second;
            }
        }
        for(int i=1;i<=n;i++)
        {
            if(i!=1)printf(" ");
            if(ans[i]==-1)ans[i]=1;
            printf("%d",ans[i]);
        }
        puts("");
    }
    return 0;
}

G - Chiaki Sequence Revisited
这个题真的强!
首先观察出每个数(除了1)出现的次数为lowbit(x)的长度,比如16为10000,那么他就会出现5次。
然后怎么做呢,既然和它的lowbit有关,那么我们就用位运算的思想做这个题,设一个数为x,那么显然x>>i就为至少出现(i+1)次的数的个数,你如果每一层都这样计算的话,实际上算的就是小于等于x的数出现次数的和。
通过这种思想,我们也可以求出小于等于x的数的和。
所以我们可以二分算出第n项是哪个数,然后再用等差数列求和算出前n项的和。

#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
long long n;
bool check(long long num)
{
    long long res=0;
    for(int i=0;i<63;i++)
    {
        res+=(num>>i);
        if(res>=n-1)return 1;
    }
    return res>=n-1;
}
long long inv(long long a,long long m)
{
    if(a==1)return 1;
    return inv(m%a,m)*(m-m/a)%m;
}

int main()
{
    int T;
    scanf("%d",&T);
    long long inv2=inv(2,mod);
    while(T--)
    {

        scanf("%lld",&n);
        if(n==1)
        {
            puts("1");
            continue;
        }
        else if(n==2)
        {
            puts("2");
            continue;
        }
        long long l=2,r=n;
        long long ans;
        while(l<=r)
        {
            long long mid=l+r>>1;
            if(check(mid))
            {
                ans=mid;
                r=mid-1;
            }
            else l=mid+1;
        }
        long long res=1;
        long long tmp=ans-1;
        long long go=1;
        for(int i=0;i<63;i++)
        {
            if((1LL<<i)>tmp)break;
            long long tmp2=(tmp>>i);
            go+=tmp2;
            //
            //if(tmp2%2)tmp2=(tmp2+1)/2*tmp2%mod;
            //else tmp2=tmp2/2*(tmp2+1)%mod;
            tmp2=tmp2%mod*((tmp2+1)%mod)%mod*inv2%mod;
            res=(res+(1LL<<i)%mod*tmp2%mod)%mod;
        }
        n=n-go;
        res=(res+n*ans%mod)%mod;
        printf("%lld\n",res);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_34921856/article/details/81989507
今日推荐