BestCoder Round #58

hdu5494 Problem 0. Card Game

怎么选择m个数都能赢,最小的m个数之和大于对方的最大的m个数之和就好了。

#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <stdlib.h>
#include <map>
#include <vector>
#define rep(i,n) for(i=0;i<n;i++)
#define cle(x) memset(x,0,sizeof(x))

#define ll long long
const int maxn=1000+5;
using namespace std;
int main()
{
#ifndef ONLINE_JUDGE
     freopen("in.txt","r",stdin);
     //freopen("out.txt","w",stdout);
#endif
    int T;
    cin>>T;
    int a[maxn],b[maxn],n,m;
    while(T--){
        cin>>n>>m;
        int i;rep(i,n)cin>>a[i];
        rep(i,n)cin>>b[i];
        int sum[maxn];
        sort(a,a+n);sort(b,b+n);
        int ip=0;rep(i,n){
            if(i==0)sum[i]=a[i];
            else sum[i]=sum[i-1]+a[i];
        }
        int sumb[maxn];
        for(i=n-1;i>=0;i--){
            if(i==n-1)sumb[ip++]=b[i];
            else sumb[ip++]=sumb[ip-1]+b[i];
        }
        if(sum[m-1]>sumb[m-1])cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
    return 0;
}

hdu 5495 Problem 1. LCS

题意

子序列,按照相同的排列顺序,重新排列,是相同子序列最长。

解法

每个环之间是独立的,在独立的一个环上的选择,最优情况要舍掉一个数字,比如1->2 2->3 3->4 4->1 序列(1,2,3,4)和序列(2,3,4,1)就要舍掉1

#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <stdlib.h>
#include <map>
#include <vector>
#define rep(i,n) for(i=0;i<n;i++)
#define cle(x) memset(x,0,sizeof(x))

#define ll long long
const int maxn=100000+5;
using namespace std;
int a[maxn],b[maxn],u[maxn];
int v[maxn];
int main()
{
#ifndef ONLINE_JUDGE
     freopen("in.txt","r",stdin);
     //freopen("out.txt","w",stdout);
#endif
    int T;
    cin>>T;
    int n;
    while(T--)
    {
        cle(v);
        cin>>n;
        int i;
        rep(i,n)
        {
            scanf("%d",&a[i]);
        }
        rep(i,n)
        {
            scanf("%d",&b[i]);
        }
        rep(i,n)
        {
            u[a[i]]=b[i];
        }
        int ans=0;
        rep(i,n)
        {
            if(a[i]==b[i])
            {
                ans++;
                v[a[i]]=1;
                continue;
            }
            if(v[a[i]]==0)
            {
                v[a[i]]=1;
                int temp=1;
                int now=u[a[i]];
                while(true)
                {
                    if(v[now])
                    {
                        break;
                    }
                    else
                    {
                        v[now]=1;
                        temp++;
                        now=u[now];
                    }
                }
                ans+=temp;
                ans--;
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}

hdu 5496 Problem 2. Beauty of Sequence

题意:

所有子序列和之和,子序列中连续相邻相同元素只算一次。

解法:

官方解法:一个数的如果是几个连续相同数的第一个,他的贡献计算。
总的方案数=之前的方案数*之后的方案数
之前的方案数=所有方案数-以和他相同数作为倒数第二个的方案数 用map统计就好了

#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <stdlib.h>
#include <map>
#include <vector>
#define rep(i,n) for(i=0;i<n;i++)
#define cle(x) memset(x,0,sizeof(x))

#define ll long long
const int maxn=100000+5;
const int mod=1e9+7;
using namespace std;
ll a[maxn];
ll b[maxn];
int n;
void init()
{
    b[0]=0;
    for(int i=1;i<maxn;i++){
        b[i]=(b[i-1]*2+1)%mod;
    }      
}
map<ll,ll>mp;
void doit()
{
    mp.clear();ll sum=0;
    for(int i=1;i<=n;i++)
    {
        ll be=(b[i-1]+1-mp[a[i]]+mod)%mod;//之前的
        ll en=b[n-i]+1;//之后的
        sum=((sum+((a[i]*((be*en)%mod))%mod))%mod);
        mp[a[i]]=(mp[a[i]]+b[i-1]+1)%mod;
    }
    cout<<sum<<endl;
}
int main()
{
#ifndef ONLINE_JUDGE
     freopen("in.txt","r",stdin);
     //freopen("out.txt","w",stdout);
#endif
    int T;cin>>T;init();
    while(T--)
    {
        cin>>n;
        for(int i=1;i<=n;i++){
            scanf("%I64d",&a[i]);
        }
        doit();
    }
    return 0;
}

hdu 5497 Problem 3. Inversion

题意:

一个序列 ,可以删除一个长度为m的连续子序列. 问如何删除才能使逆序对最少。

解法:

删掉的应该是构成逆序对最多那些
向前连线(比他大的)
向后两线(比他小的)
选择的区间可能重复计算了。连接的两端都在区间内。
删掉的数目=所有的连线(每个数向前连线+向后连线)-区间内构成的逆序对个数(一个树状数组可维护,能想到怎么维护就可以解决了)

备注:

由于我自己写的思路比较露骨,所以有时提交超时有时候AC,可以加一些输入输出挂之类的~

#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <stdlib.h>
#include <map>
#include <vector>
#define rep(i,n) for(i=0;i<n;i++)
#define cle(x) memset(x,0,sizeof(x))

#define ll long long
const int maxn=100000+5;
using namespace std;
ll a[maxn],rea[maxn];
ll b[maxn],qu[maxn];
ll sum[maxn];
int lowbit(int x){
    return x&(-x);
}
ll getsum(int x)
{
    ll re=0;
    for(int i=x-1;i>0;i-=lowbit(i))re+=sum[i];
    return re;
}
void update(int x,ll y){
    for(int i=x;i<maxn;i+=lowbit(i))sum[i]+=y;
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
     //freopen("out.txt","w",stdout);
#endif
    int T;
    cin>>T;
    while(T--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        int i;
        rep(i,n){
            scanf("%I64d",&a[i]);rea[i]=n-a[i]+1;}
        cle(sum);ll cot=0;
        for(i=n-1;i>=0;i--){
            b[i]=getsum(a[i]);cot+=b[i];
            update(a[i],1);
        }
        if(m==0||cot==0){
            printf("%I64d\n",cot);
            continue;
        }
        cle(sum);
        rep(i,n){
            b[i]+=getsum(rea[i]);//每个位置构成逆序对,向前向后之和
            update(rea[i],1);
        }
        cle(sum);qu[0]=0;
        for(i=0;i<m;i++){
            qu[0]+=getsum(rea[i]);//维护第一个m个连续的数的逆序对个数
            update(rea[i],1);
        }int ip=1;
        for(i=1;i<=n-m;i++){
            qu[ip]=qu[ip-1]-(getsum(n+1)-getsum(rea[i-1]+1));//去掉第一个数的构成个数
            update(rea[i-1],-1);
            qu[ip]+=getsum(rea[i+m-1]);//加上最新数构成个数
            update(rea[i+m-1],1);
            ip++;
        }
        ll maxans=0;ll now=0;
        for(i=0;i<m;i++)now+=b[i];
        for(i=0;i<=n-m;i++){
            maxans=max(maxans,now-qu[i]);
            now-=b[i];now+=b[i+m];
        }
        printf("%I64d\n",cot-maxans);
    }
    return 0;
}

hdu 5498 Problem 4. Tree

现如今能力不足~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值