2015 Multi-University Training Contest 6

 

1001 Average

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 2086    Accepted Submission(s): 158
Special Judge


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 (1n105), the number of soda.
The next line contains n integers a1,a2,,an (0ai109), 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 (0mn) in the second line denoting the number of operations needed. Then each of the following m lines contain two integers x and y (1x,yn), 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
 

 题意: 执行上述三种操作的其中一种操作, x给y 1个值,或者y给x 1个值,x与y必须相邻。

 解法: 不能整除不符合题意, 需要注意的细节比较多,总体上是这样, a[i]与均值作比较, 如果小1那么就从i+1那里拿,大1就给i+1, 等于的话不做任何处理。

但是对于第一个值要进行特殊处理。。  这个当时没有想清楚怎么处理, 看了题解后才晓得, , 现在就特想知道, 为什么这么想。

#include<bits/stdc++.h>
#define N 100010
#define LL long long

using namespace std;
int f[N],p[N];
int x[N],y[N];
int m,n;
LL sum;

bool work()
{
    for (int i=1;i<=n;i++) if (f[i]!=sum/n) return false;
    return true;
}

bool all_same() {
  for (int i=1; i<=n; ++ i) if (p[i]!=sum/n) return false;
  return true;
}

bool solve() {
  for (int i = 2; i<n; ++i) {
    if (f[i] == sum/n) continue;
    else if (f[i] <sum/n) x[m] = i + 1, y[m++] = i,f[i]++,f[i+1]--;
    else if (f[i] >sum/n) x[m] = i, y[m++] = i + 1,f[i]--,f[i+1]++;
  }
  if (f[n] <sum/n) x[m] = 1, y[m++] = n,f[n]++,f[1]--;
  else if (f[n] >sum/n) x[m] = n, y[m++] = 1,f[n]--,f[1]++;
  return work();
}


void print()
{
    printf("YES\n%d\n",m);
    for (int i=0;i<m;i++) printf("%d %d\n",x[i],y[i]);
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        sum=0;

        scanf("%d",&n);
        for (int i=1;i<=n;i++)
        {
            scanf("%d",&p[i]);
            sum+=p[i];
        }
        if (sum%n!=0)
        {
            printf("NO\n");
            continue;
        }
        if (all_same())
        {
            printf("YES\n0\n");
            continue;
        }
        if (p[1]>=sum/n)
        {
            for (int i=1;i<=n;i++) f[i]=p[i];
            m=0; x[m]=1; y[m++]=2; f[1]--; f[2]++; if (solve()) {print(); continue;}

        }
        if (p[1]<=sum/n)
        {
            for (int i=1;i<=n;i++) f[i]=p[i];
            m=0; x[m]=2; y[m++]=1; f[1]++; f[2]--; if (solve()) {print(); continue;}
        }
        for (int i=1;i<=n;i++) f[i]=p[i];
        m=0; if (solve()) {print(); continue;}

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

  

1003 Cake

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 1093    Accepted Submission(s): 521
Special Judge


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 (1n105,2m10), 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份,每一份的和相同, 每个值必须使用且只能使用一次。
思路:如果是1……2m 就分成2m+1, 2m-1+2, 这样的形式。。。 于是这个题也可以这样, 先分解然后当n的个数比较小时,用搜索去搜一个答案。  需要注意的是, 在搜索的时候要先使用大的数, 类似小木棍的道理。
#include<bits/stdc++.h>
#define N 50
#define LL long long

using namespace std;

vector<int> G[10];
bool visit[N];
int a[N][N];

bool dfs(int k, int sum, int n,int m)
{
    bool flag=false;
    if (k==m) return true;

    for (int i=n;i>=1;i--)
        if (!visit[i]&&sum>=i)
    {
        visit[i]=true;
        a[k][++a[k][0]]=i;
        if (sum==i) flag=dfs(k+1,(n+1)*n/2/m,n,m); else flag=dfs(k,sum-i,n,m);
        if (flag) return true;
        a[k][0]--;
        visit[i]=false;
    }
    return false;
}

int main()
{
    int T,m;
    LL n;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%I64d%d",&n,&m);
        for (int i=0;i<m;i++) G[i].clear();
        if ((n+1)*n/2%m!=0||n<2*m-1)
        {
            printf("NO\n"); continue;
        }
        while(n>40)
        {
            for (int i=0;i<m;i++) G[i].push_back(n-i);
            for (int i=0;i<m;i++) G[i].push_back(n-2*m+i+1);
            n=n-2*m;
        }
        for (int i=0;i<m;i++) a[i][0]=0;
        memset(visit,0,sizeof(visit));
        dfs(0,(n+1)*n/2/m,n,m);
        for (int i=0;i<m;i++) for (int j=1;j<=a[i][0];j++) G[i].push_back(a[i][j]);

        printf("YES\n");
        for (int i=0;i<m;i++)
        {
            printf("%d",(int)G[i].size());
            for (int j=0;j<(int)G[i].size();j++) printf(" %d",G[i][j]);
            printf("\n");
        }
    }
    return 0;
}

  

1006 First One

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 1971    Accepted Submission(s): 103


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:
i=1nj=in(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 (1n105), the number of integers in the array.
The next line contains n integers a1,a2,,an (0ai105).
 

 

Output
For each test case, output the value.
 

 

Sample Input
1 2 1 1
 

 

Sample Output
12
 
思路: 刚开始想的是对于每一个i, 枚举log2S[i,j], 然后二分出来这个范围l,r, 可以利用等差数列求和算出来, 时间复杂度n(lgn)^2, 超时。
于是, 有了一个思路就是预先处理出来那个二分的范围l,r, 是利用的扫描的一种做法, 感觉挺惊叹的, 可以利用nlgn预处理, 然后计算的时候也是这个时间复杂度。
//二分位置会超时
//时间复杂度nlgn

#include<bits/stdc++.h>
#define N 100010
#define LL long long

using namespace std;

int pos[N][40];
int f[N];

int main()
{
    int T,n;
    LL ans;
    scanf("%d",&T);
    while(T--)
    {
        ans=0;
        scanf("%d",&n);
        for (int i=1;i<=n;i++) scanf("%d",&f[i]);

        for (int k=0;k<36;k++)
        {
            LL pi=1LL<<(k+1),sum=f[1];
            int j=1;
            for (int i=1;i<=n;i++)
            {
                sum=sum-f[i-1];
                while(j<=n&&sum<pi) sum=sum+f[++j];
                pos[i][k]=j-1;
            }
        }
        for (int i=1;i<=n;i++)
        {
            LL l=i,r;
            for (int k=0;k<36;k++)
            {
                r=pos[i][k];
                ans=ans+(k+1)*((r-l+1)*(i+l)+(r-l+1)*(r-l)/2);
                l=r+1;
            }
        }
        printf("%I64d\n",ans);
    }
    return 0;
}

  

1008 Hiking

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 911    Accepted Submission(s): 352
Special Judge


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 (1n105), the number of soda. The second line constains n integers l1,l2,,ln. The third line constains n integers r1,r2,,rn. (0lirin)
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
 

 

Statistic | Submit | Clarifications | Back

 

思路: 在左端点可以到达的情况下,r越小越好, 利用这种贪心思想来做, 代码很惊艳。

#include<bits/stdc++.h>
#define N 100010

using namespace std;
struct node
{
    int l,r,z;
    bool operator<(const node &b) const
    {
        if (r<b.r) return true;
        if (r==b.r&&l<b.l) return true;
        if (r==b.r&&l==b.l&&z<b.z) return true;
        return false;
    }
};
set<node> S;
node f[N],p[N];
bool visit[N];
int ans[N];

bool cmp1(node a, node b)
{
    if (a.l<b.l) return true;
    if (a.l==b.l&&a.r<b.r) return true;
    return false;
}

bool cmp2(node a, node b)
{
    if (a.r<b.r) return true;
    if (a.r==b.r&&a.l<b.l) return true;
    return false;
}

int main()
{
    int T,n;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        memset(visit,0,sizeof(visit));
        for (int i=0;i<n;i++) scanf("%d",&f[i].l);
        for (int i=0;i<n;i++) scanf("%d",&f[i].r);
        for (int i=0;i<n;i++)
        {
            f[i].z=i+1;
            p[i]=f[i];
        }
        sort(f,f+n,cmp1);
        sort(p,p+n,cmp2);
        int now=0,pl=0,pr=0;
        while(1)
        {
            while(pl<n&&f[pl].l<=now) S.insert(f[pl++]);
            while(pr<n&&p[pr].r<now) S.erase(p[pr++]);
            if (S.empty()) break;
            visit[(*(S.begin())).z]=true;
            ans[now++]=(*(S.begin())).z;
            S.erase(S.begin());
        }
        printf("%d\n",now);
        for (int i=0;i<now;i++) printf("%d ",ans[i]);
        for (int i=1;i<=n;i++) if (!visit[i]) printf("%d ",i);
        printf("\n");
    }
    return 0;
}

/*
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
*/

  

1009 In Touch

Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 693    Accepted Submission(s): 76


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 (1in).
 

 

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 (1n2×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. (0lirin,1ci109)
 

 

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++.
 
思路: 在解题方面比较有收获的一道题目, 利用dijkstra算法的特点,每次访问的点一定是路径最优的, 每次选取没有访问过得点。
#pragma comment(linker, "/STACK:102400000,102400000")
#include<bits/stdc++.h>
#define N 200000+10
#define inf 1e15
#define LL long long

using namespace std;

int l[N],r[N];
LL  c[N],d[N];


struct node
{
    int id;
    LL dis;
    node(int id, LL dis):id(id),dis(dis){}
    bool operator <(const node &b) const
    {
        if (dis+c[id]==b.dis+c[b.id]) return id<b.id;
        return dis+c[id]<b.dis+c[b.id];
    }
};

int main()
{
    int T,n;
    scanf("%d",&T);
    while(T--)
    {
        set<node> p;
        set<int>  q;
        scanf("%d",&n);
        for (int i=1;i<=n;i++) scanf("%d",&l[i]);
        for (int i=1;i<=n;i++) scanf("%d",&r[i]);
        for (int i=1;i<=n;i++) scanf("%I64d",&c[i]);
        for (int i=1;i<=n;i++) d[i]=inf;

        d[1]=0;
        p.insert(node(1,0));
        for (int i=2;i<=n;i++) q.insert(i);
        set<int>::iterator it;
        set<int>::iterator it2;
        while(!p.empty())
        {
            int u=(*(p.begin())).id;
            LL  val=(*(p.begin())).dis;
            p.erase(p.begin());

            it=q.lower_bound(u-r[u]);
            while (it!=q.end()&&((*it>=u-r[u]&&*it<=u-l[u])||((*it>=u+l[u])&&(*it<=u+r[u]))))
            {
                d[*it]=val+c[u];
                p.insert(node(*it,d[*it]));
                it2=it++;
                q.erase(it2);
            }

            it=q.lower_bound(u+l[u]);
            while (it!=q.end()&&((*it>=u-r[u]&&*it<=u-l[u])||((*it>=u+l[u])&&(*it<=u+r[u]))))
            {
                d[*it]=val+c[u];
                p.insert(node(*it,d[*it]));
                it2=it++;
                q.erase(it2);
            }
        }
        printf("0");
        for (int i=2;i<=n;i++) if (d[i]==inf) printf(" -1"); else printf(" %I64d",d[i]);
        printf("\n");
    }
    return 0;
}

  

1011 Key Set

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 1476    Accepted Submission(s): 726


Problem Description
soda has a set S with n integers {1,2,,n}. A set is called key set if the sum of integers in the set is an even number. He wants to know how many nonempty subsets of S are key set.
 

 

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

The first line contains an integer n (1n109), the number of integers in the set.
 

 

Output
For each test case, output the number of key sets modulo 1000000007.
 

 

Sample Input
4 1 2 3 4
 

 

Sample Output
0 1 3 7
 
没有看题, 据说是最水的题目。

posted on 2015-08-08 21:52  wzb_hust  阅读(138)  评论(0编辑  收藏  举报

导航