2015 Multi-University Training Contest 6

32 篇文章 0 订阅
17 篇文章 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

题目大意:给一个有n个整数的集合S{1,2,3……n},问S中某些数的和是偶数的总数量。

思路;一看就知道一定有规律,果然:2^(n-1)-1。快速幂水过。

#include<stdio.h>
#include<string.h>
#include<math.h>
#define LL __int64 
#define mod 1000000007
LL quick(LL a,int b,LL c)
{
    a=a%c;
    LL ans=1;
    while(b){
        if(b%2==1)ans=(ans*a)%mod;
        a=(a*a)%mod;
        b=b/2;
    }
    return ans;
}
int main()
{
    int T,i,j,k,n;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        LL ans=quick(2,n-1,mod)-1;
        printf("%I64d\n",ans);
    }
    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
 

题目大意:有n块蛋糕,要等量的分成m组。

这个题当时比赛的时候直接dfs水过了。后来oj上出来再去交,居然wa了,据说是数据加强了。之后修改了半天,不是爆栈就是超时。

= =看官方题解:考虑n为2m的时候,1,2,3……2m可以均分给m组。(这是重点!!)

那么当n很大的时候,我们可以进行这么一个操作n-2m,然后把这些均分给m组。一直这么操作,当n<40的时候,这个时候就可以搜索了。

#include<stdio.h>
#include<string.h>
#define LL __int64 
int n,m,vis[100005],f,p[15][100005],s[100005],x[15][100005];

LL ave;
void dfs(int x,int cnt,int tot,int mm)
{
    int i,j;
    if(f)return;
    if(tot==ave){
        s[cnt]=mm-1;
    
        dfs(n,cnt+1,0,1);
    }
    if(cnt==m){
            f=1;return;
        }
        if(f)return;
    for(i=x;i>=1;i--)
    {
        if(!vis[i]&&tot+i<=ave){
            vis[i]=1;
            p[cnt][mm++]=i;
            dfs(i-1,cnt,tot+i,mm);
            if(f)return;
            mm--;
            vis[i]=0;
        }
    }
    return ;
}
int main()
{
    int T,i,j,k;
  
    LL sum;
    scanf("%d",&T);
    while(T--)
    {
        memset(vis,0,sizeof(vis));
        sum=0;f=0;
    scanf("%d%d",&n,&m);

    for(i=1;i<=n;i++)
    sum=sum+i;
    ave=sum/m;
    if(n>ave||sum%m!=0){    
        printf("NO\n");
        continue;
    }    //如果蛋糕中最大的那块大于平均的,那么没有一组可以拿这块蛋糕,直接判断为不行。或者不能均分给m组的情况,也是NO。
 if(n<2*m-1){
     printf("NO\n");
     continue;
 }
 k=1;
 int w=1,cont=0;
   while(n>40)
   {
       k=w;
       for(j=1;j<=m;j++)
       {
       x[j][k++]=n-2*m+j;
       x[j][k++]=n-j+1;
       if(j<m)
         k=w;
       }
       w=k;
       n=n-2*m;
       cont++;
   }
  // 这里就是一直对n进行处理:一直n-2m,同时将这些数存起来。
sum=0;
for(i=1;i<=n;i++)
sum=sum+i;
ave=sum/m;

 
    dfs(n,0,0,1);

    if(f){
    printf("YES\n");

    for(i=0;i<m;i++)
    {
        printf("%d ",s[i]+2*cont);
        for(int l=1;l<=2*cont;l++)
        printf("%d ",x[i+1][l]);
        for(j=1;j<s[i];j++)
        printf("%d ",p[i][j]);
        printf("%d",p[i][s[i]]);
        printf("\n");
    }
    }
    else printf("NO\n");
    }
}

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

题目大意:n个人想要去爬山,但是每个人都有各自的要求:对于第i个人,如果他前面不超过Li个人去,或者他前面超过了Ri个人去,他都不会去了。问最多有几个人会去爬山。

思路:对于这么个问题,自然是要先把最容易来参加的人拉进来。这个题目像什么:对于一些活动,每个活动有各自的开始和结束时间,问最多有几个活动能进行。

我们可以想到:贪心。没错,把Ri小的人都贪心过来。但是他还有一个条件,如果对于一个人,他前面没有Li个人参加,他是不会去的。看来单纯的贪心行不通。

再想一想,对于一个人来说,如果在他前面有Li个人参加,同时不超过Ri个人,那他就参加。如果在参加人数不超过Ri的情况下,他前面只要大于等于Li个人,他就会参加。

所以我们就要记录变量cur,代表当前有几个人已经参加。然后把Li==cur的人全部拉过来,与前面Li<cur的人放在一起,找到那个Ri最小的人。一直这样贪心,就可以了。

这里要建立一个优先队列,将入队的人以Ri进行排序,一旦符合条件,就将Ri最小的人出队并代表参加的人。

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#define M 100005
using namespace std;
struct node{
	int l,r,num;
	friend bool operator<(node a,node b)
	{ 	
		return a.r>b.r;
	}
}p[M];
/*bool operator < (const node &a,const node &b)
{
	return a.r>b.r;
} */
int v[M],s[M];
bool cmp(node a,node b)
{ 
    if(a.l==b.l)return a.r<b.r;
	return a.l<b.l;	
}
int main()
{
	int i,j,k,n,cur;
	int T;
	scanf("%d",&T);
	while(T--)
	{
		cur=0;
		memset(v,0,sizeof(v));
		memset(s,0,sizeof(s));
	priority_queue<node>Q;
	
		scanf("%d",&n);
		for(i=0;i<n;i++)
		{
		scanf("%d",&p[i].l);
	      p[i].num=i+1;
	}
	for(i=0;i<n;i++)
	scanf("%d",&p[i].r);
	sort(p,p+n,cmp);   //先对人按照l的大小排序。
	if(p[0].l==0)
	{
	Q.push(p[0]);
	}
	else {
		printf("0\n");
		for(i=0;i<n-1;i++)
		printf("%d ",p[i].num);
		printf("%d\n",p[n-1].num);
		continue;
	}
	i=1;
	k=0;
	int k1=0;
	while(!Q.empty())
	{
		for(;i<n&&p[i].l==cur;i++)
		Q.push(p[i]);
		while(!Q.empty())
		{
			if(Q.top().r>=cur)
			{
				v[k++]=Q.top().num;
				cur++;
				Q.pop();
				break;
			}
			else 
				s[k1++]=Q.top().num;
				Q.pop();
			
		}
		for(;i<n&&p[i].l==cur;i++)
		Q.push(p[i]);
	}
//	printf("%d %d\n",k,k1);
    for(;i<n;i++)
    s[k1++]=p[i].num;
	printf("%d\n",cur);
	for(j=0;j<k;j++)
	printf("%d ",v[j]);
	for(j=0;j<k1-1;j++)
	printf("%d ",s[j]);
   if(k1>0) printf("%d",s[k1-1]);
   printf("\n");
	}
}

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


题目大意:计算题中的式子的值。

思路:注意到式中有出现[log2S(x,y)]+1,而n最大是10^5,表明S(x,y)的最大值为10^10<2^34。跟二进制位相关。

所以我们设一个变量k,代表第几位,那么就有1<=k<=34。

考虑对一个k时,我们只需算出(i+j)的值,就能算出在这个位上的值了。如何计算总的值呢。

对于每一个k,可以从1到n对i进行枚举,对于每一个i,可以算出j的一个区间[ l , r ],满足当j>=l&&j<=r时,2^(k-1)<=sum(i,j)<=2^k-1。

所以这样通过枚举k和i,最终算出(i+j)的总和。

注意要对2^k这里进行预处理。

时间复杂度O(nlogn)。

这道题目在细节上也需要把握,我是参看别人的代码的。自己实在还欠火候= =。

#include<stdio.h>
#include<string.h>
#include<math.h>
#define max(a,b) a>b?a:b
#define LL __int64
LL fl[100]={0,0,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,524288,1048576,2097152,4194304,8388608,16777216,33554432,67108864,134217728,268435456,536870912,1073741824,2147483648,4294967296,8589934592};
LL fr[100]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535,131071,262143,524287,1048575,2097151,4194303,8388607,16777215,33554431,67108863,134217727,268435455,536870911,1073741823,2147483647,4294967295,8589934591,17179869183};
int main()
{
	LL T,i,j,k,n,m,l,r,sum[100005],a;
	scanf("%I64d",&T);
	while(T--)
	{
		memset(sum,0,sizeof(sum));
		scanf("%I64d",&n);
		for(i=1;i<=n;i++)
		{
		scanf("%I64d",&a);
	    sum[i]=sum[i-1]+a;    //计算出(1,i)的sum值。对于sum(i,j)就是sum[j]-sum[i-1]。
	    }
	    LL ans=0;
	    for(k=1;k<=34;k++)     //对k进行枚举。
	    {
    		l=1;
    		r=0;
    		for(i=1;i<=n;i++)     //对i进行枚举。
    		{
		    	l=max(i,l);
		    	while(l<=n&&sum[l]-sum[i-1]<fl[k])    //先算出左区间。
		    	l++;
		    	
		    	r=max(l,r);
		    	while(r<=n&&sum[r]-sum[i-1]>=fl[k]&&sum[r]-sum[i-1]<=fr[k])
		    	r++;
		    	r--;    
		    	if(l<=r)
		    	ans+=(i+l+i+r)*(r-l+1)/2*k;    //这里就是对区间[i+l,i+r]求和,即(i+j)的和。然后乘上k。
		    }
    	}
    	printf("%I64d\n",ans);
	}
	return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值