2015 Multi-University Training Contest 6(hdu5353-5363)

Average

Problem Description

There are n soda sitting around a round table. soda are numbered from 1 to n and i-th soda is adjacent to (i+1)-th soda, 1-st soda is adjacent to n-th soda.

Each soda has some candies in their hand. And they want to make the number of candies the same by doing some taking and giving operations. More specifically, every two adjacent soda x and y can do one of the following operations only once:
1. x-th soda gives y-th soda a candy if he has one;
2. y-th soda gives x-th soda a candy if he has one;
3. they just do nothing.

Now you are to determine whether it is possible and give a sequence of operations.

Input

There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:

The first contains an integer n (1≤n≤105), the number of soda.
The next line contains n integers a1,a2,…,an (0≤ai≤109), where ai denotes the candy i-th soda has.

Output

For each test case, output “YES” (without the quotes) if possible, otherwise output “NO” (without the quotes) in the first line. If possible, then the output an integer m (0≤m≤n) in the second line denoting the number of operations needed. Then each of the following m lines contain two integers x and y (1≤x,y≤n), which means that x-th soda gives y-th soda a candy.

Sample Input

3
6
1 0 1 0 0 0
5
1 1 1 1 1
3
1 2 3

Sample Output

NO
YES
0
YES
2
2 1
3 2
这个题比较吊。。。暴力枚举,1给N一个,N给1一个,他两个谁都不给,然后从1-N扫一遍,如果当前这个大于平均值,那么给它下一个人一个,如果小,从他下一个人拿一个。
代码略。。。

Cake

Problem Description

There are m soda and today is their birthday. The 1-st soda has prepared n cakes with size 1,2,…,n. Now 1-st soda wants to divide the cakes into m parts so that the total size of each part is equal.

Note that you cannot divide a whole cake into small pieces that is each cake must be complete in the m parts. Each cake must belong to exact one of m parts.

Input

There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:

The first contains two integers n and m (1≤n≤105,2≤m≤10), the number of cakes and the number of soda.
It is guaranteed that the total number of soda in the input doesn’t exceed 1000000. The number of test cases in the input doesn’t exceed 1000.

Output

For each test case, output “YES” (without the quotes) if it is possible, otherwise output “NO” in the first line.

If it is possible, then output m lines denoting the m parts. The first number si of i-th line is the number of cakes in i-th part. Then si numbers follow denoting the size of cakes in i-th part. If there are multiple solutions, print any of them.

Sample Input

4
1 2
5 3
5 2
9 3

Sample Output

NO
YES
1 5
2 1 4
2 2 3
NO
YES
3 1 5 9
3 2 6 7
3 3 4 8
把1-N(尺寸等于编号)平均分给M个人,输出分配方案
这个题,比赛的时候过了好多,但是结束之后再交,大部分代码都是错的,下面的博客写得非常详细
先来个官方题解:
这里写图片描述
下面的内容转自:hdu5355 Cake
解题思路:此题无解的情况无外乎两种:①所有蛋糕的大小之和无法被m整除;②每一份蛋糕的大小之和不得小于蛋糕大小的最大值n,即sum/m>=n,转化一下为n*m<=sum,亦可以将sum代入,转化为n>=2*m-1。

之后便是有解的情况,有解的情况每份蛋糕的大小之和是知道的,即sum/m。然后我们可以知道n最小得是2*m-1,举个例子就很清楚了,譬如n=5,m=3,

5 3

1 5

2 4 1

2 3 2

2*m-1就说明了n本身可以自己一组,其他两两一组,一个正向递增,一个反向递减,必定可以凑成n,当然这是奇数的情况

但该方法其实是不分奇偶性的,上述只是说明。其实我们需要做的就是把分配方式分成两部分,一部分是k个2*m,另外就是剩下的那部分,我们来看看n=23,m=6这组数据,之前AC的代码普遍过不了这组数据

23 6
YES
3 11 12 23
4 10 1 13 22
4 9 2 14 21
4 8 3 15 20
4 7 4 16 19
4 6 5 17 18

先利用(n-m*2+1)%(m*2)+m*2-1算出粉色那部分数据的大小,然后利用贪心的思想二分一下即可找到符合的蛋糕大小,剩下的绿色部分则是k个2*m的部分,该部分小的数是正向递增的,大的数是反向递减的,所以必定是符合要求的。为了更加直观,放上n=100,m=5的数据

100 5
YES
20 10 1 11 100 12 99 13 98 14 97 15 96 16 95 17 94 18 93 19 92
20 9 2 20 91 21 90 22 89 23 88 24 87 25 86 26 85 27 84 28 83
20 8 3 29 82 30 81 31 80 32 79 33 78 34 77 35 76 36 75 37 74
20 7 4 38 73 39 72 40 71 41 70 42 69 43 68 44 67 45 66 46 65
20 6 5 47 64 48 63 49 62 50 61 51 60 52 59 53 58 54 57 55 56

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=100010;
const int maxm=1010;
const int MOD=1e9+7;
const int INF=0x3f3f3f3f;
int N,M;
int ans[maxn];
void solve()
{
    LL sum=1LL*(1+N)*N/2;
    if(sum%M||N<2*M-1)
    {
        printf("NO\n");
        return ;
    }
    int C=(N-2*M+1)%(2*M)+2*M-1;
    int S=C*(C+1)/2/M;
    int D=(N-C)/2/M;
    printf("YES\n");
    int K=C+1;
    set<int> sp;
    for(int i=1;i<=C;i++)sp.insert(i);
    for(int i=1;i<=M;i++)
    {
        int cnt=0;
        for(int all=0;all<S;)
        {
            auto it=sp.upper_bound(S-all);
            all+=ans[cnt++]=*(--it);
            sp.erase(it);
        }
        printf("%d",cnt+2*D);
        for(int j=0;j<cnt;j++)
            printf(" %d",ans[j]);
        for(int j=0;j<D;j++)
            printf(" %d %d",K++,N--);
        printf("\n");
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&N,&M);
        solve();
    }
    return 0;
}

First One

Problem Description

soda has an integer array a1,a2,…,an. Let S(i,j) be the sum of ai,ai+1,…,aj. Now soda wants to know the value below:

ni=1nj=i(log2S(i,j)+1)×(i+j)

Note: In this problem, you can consider log20 as 0.

Input

There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:

The first line contains an integer n (1≤n≤105), the number of integers in the array.
The next line contains n integers a1,a2,…,an (0≤ai≤105).

Output

For each test case, output the value.

Sample Input

1
2
1 1

Sample Output

12

思路:尺取法,因为 logS(i,j)2 在一定区间内是一样的,所以我们可以枚举区间,最多 20235 ,然后扫一遍原序列,每次把处于相同区间的找出来就行了

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=100010;
const int maxm=1010;
const int MOD=1e9+7;
const int INF=0x3f3f3f3f;
int N,a[maxn];
LL pow2[40];
LL sum[maxn];
int main()
{
    int T;
    scanf("%d",&T);
    pow2[0]=1;
    for(int i=1;i<40;i++)pow2[i]=pow2[i-1]*2;
    while(T--)
    {
        scanf("%d",&N);
        for(int i=1;i<=N;i++)scanf("%d",&a[i]);
        for(int i=1;i<=N;i++)sum[i]=sum[i-1]+a[i];
        LL ans=0;
        for(int i=1;i<=35;i++)
        {
            if(pow2[i]>sum[N])break;
            int l=0,r=0;
            LL tmp=0;
            for(int j=1;j<=N;j++)
            {
                while(l<=N&&sum[l]-sum[j-1]<pow2[i])l++;
                while(r+1<=N&&sum[r+1]-sum[j-1]<pow2[i+1])r++;
                if(l<=r)tmp+=1LL*(r+l*1LL)*(r-l+1LL)/2LL+j*(r-l+1LL);
            }
            ans+=tmp*i;
        }
        for(int i=1;i<=N;i++)
            ans+=1LL*(N+i)*(N-i+1LL)/2+i*1LL*(N-i+1);
        printf("%I64d\n",ans);
    }
    return 0;
}

Hiking

Problem Description

There are n soda conveniently labeled by 1,2,…,n. beta, their best friends, wants to invite some soda to go hiking. The i-th soda will go hiking if the total number of soda that go hiking except him is no less than li and no larger than ri. beta will follow the rules below to invite soda one by one:
1. he selects a soda not invited before;
2. he tells soda the number of soda who agree to go hiking by now;
3. soda will agree or disagree according to the number he hears.

Note: beta will always tell the truth and soda will agree if and only if the number he hears is no less than li and no larger than ri, otherwise he will disagree. Once soda agrees to go hiking he will not regret even if the final total number fails to meet some soda’s will.

Help beta design an invitation order that the number of soda who agree to go hiking is maximum.

Input

There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:

The first contains an integer n (1≤n≤105), the number of soda. The second line constains n integers l1,l2,…,ln. The third line constains n integers r1,r2,…,rn. (0≤li≤ri≤n)
It is guaranteed that the total number of soda in the input doesn’t exceed 1000000. The number of test cases in the input doesn’t exceed 600.

Output

For each test case, output the maximum number of soda. Then in the second line output a permutation of 1,2,…,n denoting the invitation order. If there are multiple solutions, print any of them.

Sample Input

4
8
4 1 3 2 2 1 0 3
5 3 6 4 2 1 7 6
8
3 3 2 0 5 0 3 6
4 5 2 7 7 6 7 6
8
2 2 3 3 3 0 0 2
7 4 3 6 3 2 2 5
8
5 6 5 3 3 1 2 4
6 7 7 6 5 4 3 5

Sample Output

7
1 7 6 5 2 4 3 8
8
4 6 3 1 2 5 8 7
7
3 6 7 1 5 2 8 4
0
1 2 3 4 5 6 7 8
思路:优先队列,先按照l排序,然后对于当前同意的人数cur,如果满足 cura[i].l 的,都加入队列,每次取出r最小的

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=100010;
const int maxm=1010;
const int MOD=1e9+7;
const int INF=0x3f3f3f3f;
int N;
int ans[maxn];
bool vis[maxn];
struct node
{
    int l,r,id;
    bool operator>(const node &a)const
    {
        return r>a.r;
    }
}a[maxn];
bool cmp(const node &a,const node &b)
{
    if(a.l!=b.l)return a.l<b.l;
    return a.r<b.r;
}
priority_queue<node,vector<node>,greater<node> > q;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        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);
        for(int i=1;i<=N;i++)a[i].id=i;
        sort(a+1,a+1+N,cmp);
        memset(vis,0,sizeof(vis));
        int cur=0;
        while(!q.empty())q.pop();
        int i=1;
        while(i<=N&&cur>=a[i].l)q.push(a[i]),i++;
        while(!q.empty())
        {
            node tmp=q.top();q.pop();
            if(cur<=tmp.r)
            {
                ans[++cur]=tmp.id;
                vis[tmp.id]=1;
                while(i<=N&&cur>=a[i].l)q.push(a[i]),i++;
            }
        }
        printf("%d\n",cur);
        for(int i=1;i<=N;i++)
            if(!vis[i])ans[++cur]=i;
        for(int i=1;i<=N;i++)
        {
            printf("%d",ans[i]);
            if(i!=N)printf(" ");
            else printf("\n");
        }
    }
    return 0;
}

In Touch

Problem Description

There are n soda living in a straight line. soda are numbered by 1,2,…,n from left to right. The distance between two adjacent soda is 1 meter. Every soda has a teleporter. The teleporter of i-th soda can teleport to the soda whose distance between i-th soda is no less than li and no larger than ri. The cost to use i-th soda’s teleporter is ci.

The 1-st soda is their leader and he wants to know the minimum cost needed to reach i-th soda (1≤i≤n).

Input

There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:

The first line contains an integer n (1≤n≤2×105), the number of soda.
The second line contains n integers l1,l2,…,ln. The third line contains n integers r1,r2,…,rn. The fourth line contains n integers c1,c2,…,cn. (0≤li≤ri≤n,1≤ci≤109)

Output

For each case, output n integers where i-th integer denotes the minimum cost needed to reach i-th soda. If 1-st soda cannot reach i-the soda, you should just output -1.

Sample Input

1
5
2 0 0 0 1
3 1 1 0 5
1 1 1 1 1

Sample Output

0 2 1 1 -1

Hint

If you need a larger stack size,
please use #pragma comment(linker, “/STACK:102400000,102400000”) and submit your solution using C++.

这个题也有点神
显然这么大的数据量是不可能直接求最短路的,那么应该怎么求
对于当前到达的点,例如起点1,那么1所能到达的那个范围内的点的花费是相同的,而且如果按照dis[u]+cost[u]的优先队列来更新,那么一个点被更新之后,就不会被第二次更新,所以可以利用并查集将这些相同的点压缩成一个点,那么下次再更新这一群点的话就可以跳过,不用加入到优先队列里了

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<functional>
#include<cstdlib>
#include<set>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
typedef long long LL;
typedef pair<long long,int> pii;
const int maxn=200010;
const int maxm=1010;
const int MOD=1e9+7;
const LL INF=1e18;
int N;
int pre[maxn];
struct node
{
    int l,r,c;
}a[maxn];
LL dis[maxn];
int find(int x)
{
    if(x==pre[x])return x;
    return pre[x]=find(pre[x]);
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        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);
        for(int i=1;i<=N;i++)scanf("%d",&a[i].c);
        for(int i=0;i<=N;i++)pre[i]=i;
        for(int i=0;i<=N;i++)dis[i]=INF;
        dis[1]=a[1].c;
        priority_queue<pii,vector<pii>,greater<pii> > q;
        q.push(make_pair(0LL,1));

        while(!q.empty())
        {
            pii tmp=q.top();q.pop();
            int u=tmp.second;
            for(int i=-1;i<=1;i+=2)
            {
                int l=a[u].l*i+u;
                int r=a[u].r*i+u;
                if(l>r)swap(l,r);
                l=max(l,1);l=min(l,N+1);
                if(l>r)continue;
                for(int v=l;;v++)
                {
                    v=find(v);
                    if(v<=0||v>N||v>r)break;
                    //刚开始想不明白致力为什么事用a[v].c来更新,其实是因为这里相当于点的权值,
                    //优先队列弹出的应该是到目前为止最小的,来更新后面的点,那么就要加上他自己
                    if(dis[v]>dis[u]+a[v].c)
                    {
                        dis[v]=dis[u]+a[v].c;
                        q.push(make_pair(dis[v],v));
                    }
                    pre[find(v)]=find(v+1);
                }
            }
        }
        printf("0");
        for(int i=2;i<=N;i++)
            printf(" %I64d",dis[i]!=INF?dis[i]-a[i].c:-1);
        printf("\n");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值