2015 Multi-University Training Contest 6

官方题解:2015 Multi-University Training Contest 6 solutions BY ZJU



1001 Average

HDU 5353:http://acm.hdu.edu.cn/showproblem.php?pid=5353

题意:n个人围成一圈,每对相邻两人可以且最多交换一个糖果,现求一个合法的交换顺序让所有人的糖果数相同(不能则输出NO)

\(1\leqslant n \leqslant 10^5\)


枚举第一人与第二人的三种交换情况。判断哪种能让糖果数相等

其他人若想要全部相等,按照贪心,剩下的交换情况便会固定。

注意全为0时不能交换。所以应把第一人与第二人什么都不做的情况放在最前面


#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#include<string>
#include<map>
using namespace std;
#define MAX(a,b) ((a>b)?(a):(b))
#define MIN(a,b) ((a<b)?(a):(b))
#define pb push_back
#define LL __int64
#define N 100005
#define INF 1<<30

int op[N];
int a[N];
int b[N];

int main() {
    //freopen("C:\\Users\\F\\Desktop\\in.txt", "r", stdin);
    //freopen("C:\\Users\\F\\Desktop\\out.txt", "w", stdout);
    int T;
    int n,m;
    LL sum;
    scanf("%d",&T);
    while(T--) {
        sum=0;
        scanf("%d",&n);
        for(int i=1; i<=n; ++i) {
            scanf("%d",&a[i]);
            sum+=a[i];
        }
        if(sum%n!=0) {
            printf("NO\n");
            continue;
        }

        LL ave=sum/n;
        int flag=0;
        for(int i=1; i<=n; ++i) {
            a[i]=a[i]-ave;
            if(abs(a[i])>2)flag=1;
        }
        if(flag) {
            printf("NO\n");
            continue;
        }

        for(int i=1; i<=3; ++i) {
            memcpy(b,a,sizeof(a));
            m=0;
            if(i==1) op[1]=0;                       //注意全为0时不能交换
            if(i==2) op[1]=1,b[1]--,b[2]++,m=1;
            if(i==3) op[1]=-1,b[1]++,b[2]--,m=1;


            for(int j=2; j<=n; ++j) {
                int next=((j==n)?1:j+1);
                if(b[j]==-1)        op[j]=-1,b[j]++,b[next]--,m++;
                else if(b[j]==1)    op[j]=1,b[j]--,b[next]++,m++;
                else if(b[j]==0)    op[j]=0;
            }

            flag=0;
            for(int j=1; j<=n; ++j) {
                if(b[j]!=0) {
                    flag=1;
                    break;
                }
            }
            if(!flag)
                break;
        }


        if(flag) {
            printf("NO\n");
            continue;
        }

        printf("YES\n");
        printf("%d\n",m);
        for(int i=1; i<=n; ++i) {
            int next=((i==n)?1:i+1);
            if(op[i]==-1)   printf("%d %d\n",next,i);
            if(op[i]==1)    printf("%d %d\n",i,next);
        }
    }
    return 0;
}



1003 Cake

HDU 5355:http://acm.hdu.edu.cn/showproblem.php?pid=5355

题意:有n个数1~n,将其分成m组,使每组的和相等

\(1\leqslant n \leqslant 10^5,1\leqslant m \leqslant 10\)

(待修改)


1008 Hiking

HDU 5360:http://acm.hdu.edu.cn/showproblem.php?pid=5360

题意:邀请\(n\)个人去远足,但每个人都有一个条件:在他之前有至少\(l_i\)个人接受邀请,但不超过\(r_i\)个人接受邀请。一个人只要接受了就不能反悔,无论最后的结果是否满足条件。询问一个邀请顺序使最多的人接受邀请。

\(1\leqslant n \leqslant 10^5\)


贪心


先按\(l_i\)升序排列

然后对于当前已接受邀请人数\(cnt\),取满足\(cnt \geqslant l_i\)且\(r_i\)最小的人为下一个邀请目标

可以用优先队列来实现


#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#include<string>
#include<map>
using namespace std;
#define MAX(a,b) ((a>b)?(a):(b))
#define MIN(a,b) ((a<b)?(a):(b))
#define pb push_back
#define LL __int64
#define N 100005
#define INF 1<<30


struct node{
    int l,r,id;
    friend bool operator< (node n1, node n2)
    {
        return n1.r > n2.r;
    }
}a[N];

bool cmp(node a,node b){
    if(a.l!=b.l)
        return a.l<b.l;
    return a.r<b.r;
}

int ans[N];
int ansn=1,cnt=0;
priority_queue<node> q;
int vis[N];

int main(){
	//freopen("C:\\Users\\F\\Desktop\\in.txt", "r", stdin);
	//freopen("C:\\Users\\F\\Desktop\\out.txt", "w", stdout);
	int n;
	int T;
	scanf("%d",&T);
	while(T--){
        while(!q.empty())q.pop();
        memset(vis,0,sizeof(vis));
        ansn=1;
        cnt=0;

        scanf("%d",&n);
        for(int i=1;i<=n;++i)scanf("%d",&a[i].l);
        for(int i=1;i<=n;++i){
            scanf("%d",&a[i].r);
            a[i].id=i;
        }

        sort(a+1,a+n+1,cmp);


        if(a[1].l==0)
            q.push(a[1]);
        int k=2;
        node now;

        while(!q.empty()){
            now=q.top();
            while(!(cnt>=now.l&&cnt<=now.r)&&(!q.empty())){
                q.pop();
                if(!q.empty())
                    now=q.top();
            }
            if(!q.empty()){
                ans[ansn++]=now.id;
                q.pop();
                cnt++;
            }
            while(cnt>=a[k].l&&k<=n)
                q.push(a[k++]);
        }


        printf("%d\n",cnt);
        int first=1;
        for(int i=1;i<=ansn-1;++i){
            if(!first)printf(" ");
            printf("%d",ans[i]);
            vis[ans[i]]=1;
            first=0;
        }
        for(int i=1;i<=n;++i){
            if(!vis[i]){
                if(!first)printf(" ");
                printf("%d",i);
                first=0;
            }

        }
        printf("\n");
	}
	return 0;
}


1011 Key Set

HDU 5363:http://acm.hdu.edu.cn/showproblem.php?pid=5363

题意:一个集合S包含n个数1~n,当一个集合里数的和为偶数时这个集合被称作Key Set,现在问集合S有多少个非空子集是Key Set

\(1\leqslant n \leqslant 10^9\)


通过观察数据可以得出通项公式\(a_n=2^n-1\)

用快速幂便可得出答案


#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#include<string>
#include<map>
using namespace std;
#define MAX(a,b) ((a>b)?(a):(b))
#define MIN(a,b) ((a<b)?(a):(b))
#define pb push_back
#define LL __int64
#define N 100005
#define INF 1<<30
#define MOD 1000000007

LL pm(LL a,LL b)
{
    LL ret=1;
    while(b){
        if(b&1) ret=ret*a%MOD;
        a=a*a%MOD;
        b=b>>1;

    }
    return ret;
}

int main()
{
    int T,n;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        LL ans=(pm(2,n-1)-1+MOD)%MOD;
        printf("%I64d\n",ans);
    }
    return 0;
}


(待续。。。)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值