Codeforces Round #307 (Div. 2)

A. GukiZ and Contest
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Professor GukiZ likes programming contests. He especially likes to rate his students on the contests he prepares. Now, he has decided to prepare a new contest.

In total, n students will attend, and before the start, every one of them has some positive integer rating. Students are indexed from 1 to n. Let's denote the rating of i-th student as ai. After the contest ends, every student will end up with some positive integer position. GukiZ expects that his students will take places according to their ratings.

He thinks that each student will take place equal to . In particular, if student A has rating strictly lower then student BA will get the strictly better position than B, and if two students have equal ratings, they will share the same position.

GukiZ would like you to reconstruct the results by following his expectations. Help him and determine the position after the end of the contest for each of his students if everything goes as expected.

Input

The first line contains integer n (1 ≤ n ≤ 2000), number of GukiZ's students.

The second line contains n numbers a1, a2, ... an (1 ≤ ai ≤ 2000) where ai is the rating of i-th student (1 ≤ i ≤ n).

Output

In a single line, print the position after the end of the contest for each of n students in the same order as they appear in the input.

Sample test(s)
input
3
1 3 3
output
3 1 1
题意:给出每个人的分数,让你按分数从高往低进行排名,分数相同的并列
#pragma comment(linker, "/STACK:1024000000,1024000000") 
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<stdlib.h>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<string>
using namespace std;

#define LL long long
#define ULL unsigned long long
struct sw{
	int a,loc,rank;
}t[2005];
int n;
int cmp1(const void *aa,const void *bb){
	return ((sw *)bb)->a-((sw *)aa)->a;
}
int cmp2(const void *aa,const void *bb){
	return ((sw *)aa)->loc-((sw *)bb)->loc;
}
int main(void){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&t[i].a);
		t[i].loc=i;
	}
	qsort(t+1,n,sizeof(t[0]),cmp1);
	for(int i=1;i<=n;i++)
		if(t[i].a==t[i-1].a)
			t[i].rank=t[i-1].rank;
		else t[i].rank=i;
	qsort(t+1,n,sizeof(t[0]),cmp2);
	for(int i=1;i<=n;i++)
		printf("%d ",t[i].rank);
		
	return 0;
}



B. ZgukistringZ
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Professor GukiZ doesn't accept string as they are. He likes to swap some letters in string to obtain a new one.

GukiZ has strings ab, and c. He wants to obtain string k by swapping some letters in a, so that k should contain as many non-overlapping substrings equal either to b or c as possible. Substring of string x is a string formed by consecutive segment of characters from x. Two substrings of string x overlap if there is position i in string x occupied by both of them.

GukiZ was disappointed because none of his students managed to solve the problem. Can you help them and find one of possible stringsk?

Input

The first line contains string a, the second line contains string b, and the third line contains string c (1 ≤ |a|, |b|, |c| ≤ 105, where |s|denotes the length of string s).

All three strings consist only of lowercase English letters.

It is possible that b and c coincide.

Output

Find one of possible strings k, as described in the problem statement. If there are multiple possible answers, print any of them.

Sample test(s)
input
aaa
a
b
output
aaa
题意:给出三串字符串a,b,c,你可以把a中任意挑两个字符交换,可交换多组字符,最后使得里面含有的b,c串最多
思路:a相当于可以打乱重组,所以只要统计每个字符有多少个,最后组合就行了。然后要得出b+c串个数最多,也需要先分别统计b跟c各自含有的每个字符个数。然后算出a最多含有bmax个b串,以bmax为上界枚举B串个数,算出对应的c串个数cmax,当tb+cmax>ans,记下tb跟cmax,最后输出tb串b,cmax串c,然后算出a中还剩余多少个字母,把它们依次输出即可
By senwil, contest: Codeforces Round #307 (Div. 2), problem: (B) ZgukistringZ, Accepted, #
 #pragma comment(linker, "/STACK:1024000000,1024000000") 
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<stdlib.h>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<string>
using namespace std;

#define LL long long
#define ULL unsigned long long
char a[100005],b[100005],c[100005];
int ca[26],cb[26],cc[26];
int cha[26],ma,mb;
int ans,ta,tb;
int coub,couc;
int main(void){
    scanf("%s%s%s",a,b,c);
    for(int i=0;a[i];i++)
        ca[a[i]-'a']++;
    for(int i=0;b[i];i++)
        cb[b[i]-'a']++;
    for(int i=0;c[i];i++)
        cc[c[i]-'a']++;
    int flag=1;
    for(int i=0;i<26;i++)
        if(cb[i]){
            if(flag){
                flag=0;
                ma=ca[i]/cb[i];
            }
            else ma=min(ma,ca[i]/cb[i]);
        }
    
    for(;ma>=0;ma--){
        for(int i=0;i<26;i++)
            cha[i]=ca[i]-cb[i]*ma;
        mb=0;
        flag=1;
        for(int i=0;i<26;i++)
            if(cc[i]){
                if(flag){
                    flag=0;
                    mb=cha[i]/cc[i];
                }
                else mb=min(mb,cha[i]/cc[i]);
            }
        if(ma+mb>ans){
            ans=ma+mb;
            ta=ma,tb=mb;
        }
    }
    
    for(int i=0;i<ta;i++)
        printf("%s",b);
    for(int i=0;i<tb;i++)
        printf("%s",c);
    for(int i=0;i<26;i++)
        cha[i]= ca[i]-ta*cb[i]-tb*cc[i];
    for(int i=0;i<26;i++)
        for(int j=0;j<cha[i];j++)
            printf("%c",'a'+i);
    
    
    
    return 0;
}


C. GukiZ hates Boxes
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Professor GukiZ is concerned about making his way to school, because massive piles of boxes are blocking his way.

In total there are n piles of boxes, arranged in a line, from left to right, i-th pile (1 ≤ i ≤ n) containing ai boxes. Luckily, m students are willing to help GukiZ by removing all the boxes from his way. Students are working simultaneously. At time 0, all students are located left of the first pile. It takes one second for every student to move from this position to the first pile, and after that, every student must start performing sequence of two possible operations, each taking one second to complete. Possible operations are:

  1. If i ≠ n, move from pile i to pile i + 1;
  2. If pile located at the position of student is not empty, remove one box from it.

GukiZ's students aren't smart at all, so they need you to tell them how to remove boxes before professor comes (he is very impatient man, and doesn't want to wait). They ask you to calculate minumum time t in seconds for which they can remove all the boxes from GukiZ's way. Note that students can be positioned in any manner after t seconds, but all the boxes must be removed.

Input

The first line contains two integers n and m (1 ≤ n, m ≤ 105), the number of piles of boxes and the number of GukiZ's students.

The second line contains n integers a1, a2, ... an (0 ≤ ai ≤ 109) where ai represents the number of boxes on i-th pile. It's guaranteed that at least one pile of is non-empty.

Output

In a single line, print one number, minimum time needed to remove all the boxes in seconds.

Sample test(s)
input
2 1
1 1
output
4
题意:给出n堆盒子和m个学生,每堆盒子含有的盒子数为ai,每个学生有两种行动方式,一种是拿走当前一个盒子,一个是跳到下一堆盒子,每种行动都消耗1秒,初始时学生都站在第一个盒子左边,问最少需要多少秒可以把盒子全拿完
思路:想直接算的话很容易往DP或贪心的方向去想,不过这样很难算出最优解是什么。换个方法,用二分求出结果后,判断该情况是否可行,当知道共需要多少秒的时候,我们就需要每个学生尽可能的拿的多,你可以从前往后拿,也可以从后往前拿,因为从前往后拿每拿完一堆你需要向后跳一格所以处理起来比较麻烦,所以我选择从后往前拿,这样只要走到最后一个不空的盒子,拿完之后往前面的拿的时候,不用再算步数。我们枚举m个学生,每次让他们从最后一个不空的的盒子堆开始拿,拿完往前,直到次数用尽,当成功到达第一个盒子左边时,该方案即为成功,当盒子没拿完或最后一个盒子的位置大于你的时间时失败。
#pragma comment(linker, "/STACK:1024000000,1024000000") 
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<stdlib.h>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<string>
using namespace std;

#define LL long long
#define ULL unsigned long long
int n,m;
LL a[100005];
LL b[100005];
bool isok(LL x){
    for(int i=1;i<=n;i++) b[i]=a[i];
    int cur=n;
    LL tmp;
    for(int i=1;i<=m;i++){
        while(cur>=1&&b[cur]==0)
            cur--;
        if(cur==0) return 1;
        if(cur>x) return 0;
        tmp = cur;
        while(cur>0&&b[cur]+tmp<=x){
            tmp+=b[cur];
            cur--;
            
        }
        if(cur==0) return 1;
        b[cur]-=(x-tmp);
        
    }
    return 0;
}
int main(void){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%I64d",&a[i]);
    LL l=0,r=(1LL<<60);
    while(l<=r){
        LL mid = (l+r)>>1;
        if(isok(mid)) r=mid-1;
        else l=mid+1;
    }
    printf("%I64d\n",l);    
    return 0;
}



D. GukiZ and Binary Operations
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

We all know that GukiZ often plays with arrays.

Now he is thinking about this problem: how many arrays a, of length n, with non-negative elements strictly less then 2l meet the following condition: ? Here operation  means bitwise AND (in Pascal it is equivalent to and, in C/C++/Java/Python it is equivalent to &), operation  means bitwise OR (in Pascal it is equivalent to , inC/C++/Java/Python it is equivalent to |).

Because the answer can be quite large, calculate it modulo m. This time GukiZ hasn't come up with solution, and needs you to help him!

Input

First and the only line of input contains four integers nklm (2 ≤ n ≤ 10180 ≤ k ≤ 10180 ≤ l ≤ 641 ≤ m ≤ 109 + 7).

Output

In the single line print the number of arrays satisfying the condition above modulo m.

Sample test(s)
input
2 1 2 10
output
3
题意:你可以任意挑选小于2^l的n个数,让它们以这个公式 ,两两取与再取或的方式最后答案为k,问你有多少种方案数,答案取余m
思路:这题看了别人的题解之后终于明白了。首先,我们把k转换为二进制来看,若某一位为1,则必须存在n个数中至少有相邻的两个数那一位都为1,若某一位为0,组必须存在n个数它们不能有相邻的两个数那一位都为1.这样我们相当于求k每一位在n个数字中的方案数,答案是每一位的方案数相乘起来。 网上直接给出当k某一位为0时有n个数的方案数满足斐波那契数,这里我按照自己的理解推了一番。
我用dp[i][j]表示有i个数,j表示最后一个数为0还是为1时满足没有相邻为1的方案数,因为n>=2,所以i只有大于2才有意义。首先dp[1][0]=1,dp[1][1]=1 , dp[2][0]=dp[1][0]+dp[1][1],dp[2][1]=dp[1][0] ………… 通项公式就是dp[n][0]=dp[n-1][0]+dp[n-1][1],dp[n][1]=dp[n-1][0] ,意思是当你长度为n最后一个数字为0时,你可以在长度为n-1最后一个数字为0或为1后面补0,这样不存在相邻为1的方案,若最后一位要为1,就只能在n-1最后一位为0的时候补1,这样才不会有相邻的1。最后你要计算的是all[n]=dp[n][0]+dp[n][1],其中dp[n][0]==all[n-1],dp[n][1]==dp[n-1][0]==all[n-2],推出all[n]=all[n-1]+all[n-2],这就是斐波那契数列。但这初始值有些不同,all[n] = fib[n+1] ,fib第0个元素跟第1个元素为1. 算出不相邻的方案之后,只要算出总的方案数2^n(每一位取0或取1)减去不相邻的方案,即为相邻的方案。你也可以用dp去推一下,我稍微提一下,我用c[n]表示长度为n时具有相邻1的方案数,c[2]=1 , c[3]=c[2]*2+dp[2][1]………… c[n]=c[n-1]*2+dp[n-1][1]=c[n-1]*2+all[n-3]这里的dp是上面求的不存在相邻的1,由于c[n-1]具有相邻的1所以下一位任意,dp[n-1][1]是长度为n-1最后一位为1,我们补1让它有相邻的1.
得出是斐波那契数列之后,我们可以用矩阵快速幂求解斐波那契数,也可以用矩阵快速幂求c
注意:这道题wa点挺多的,首先是UNSIGNED LONG LONG在判断是否越界的时候用,还有快速幂的次数是long long,枚举l位时候,第63位已经暴了10^18,所以需要特判。最后输出结果要%mod,不然它有mod为1且l=0的样例
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
using namespace std;
#define MAXN 2
#define MAXM 2
#define LL long long
LL mod;
LL mult_mod(LL a,LL b,LL c)
{
    a %= c;
    b %= c;
    LL ret = 0;
    LL tmp = a;
    while(b)
    {
        if(b & 1)
        {
            ret += tmp;
            if(ret > c)ret -= c;//直接取模慢很多
        }
        tmp <<= 1;
        if(tmp >=c)tmp -= c;
        b >>= 1;
    }
    return ret;
}
LL mypow(LL a,LL b){
	if(b==1) return a;
	else if(b%2) return a*mypow(a*a%mod,b/2)%mod;
	else return mypow(a*a%mod,b/2);
}
struct Mat{
	int n,m;
	long long mat[MAXN][MAXM];
	Mat(){};
	Mat(int _n){
		n=_n;
		m=_n;
		memset(mat,0,sizeof(mat));
	}	
	Mat(int _n,int _m){
		n=_n;
		m=_m;
		memset(mat,0,sizeof(mat));
	}	
};
Mat mult(Mat a , Mat b){
	Mat res = Mat(a.n,b.m);
	for(int i=0;i<a.n;i++)
		for(int k=0;k<a.m;k++)
			if(a.mat[i][k]!=0)
				for(int j=0;j<b.m;j++)
					if(b.mat[k][j]!=0)
						res.mat[i][j]=(res.mat[i][j]+a.mat[i][k]*b.mat[k][j]%mod)%mod;
	//如果快速幂里相乘超MOD,可用mult_mod 
	return res;
						
}
Mat pow_m(Mat a,int n){
	Mat res = Mat(a.n);
	for(int i=0;i<a.n;i++)
		res.mat[i][i]=1;
	while(n){
		if(n&1) res=mult(res,a);
		a=mult(a,a);
		n>>=1;
	}
	return res;
}

int last(long long x){
	return (x%mod+mod)%mod;
}
int main(void){
	LL n,k;
	int l;
	scanf("%I64d%I64d%d%I64d",&n,&k,&l,&mod);
	if(k>(1LL<<l)){
		printf("0\n");
		return 0;
	}
	Mat res = Mat(2);
	res.mat[0][0]=res.mat[0][1]=res.mat[1][0]=1;
	res = pow_m(res,n);
	LL a = (res.mat[0][0]+res.mat[0][1])%mod;
	LL b = ((mypow(2,n)-a)%mod+mod)%mod;
	LL ans = 1;
	for(int i=0;i<l;i++)
		if(i==63||((1<<i)&k)==0)
			ans=(ans*a)%mod;
		else ans=(ans*b)%mod;
	printf("%I64d\n",ans);
	
	return 0;
}



E. GukiZ and GukiZiana
time limit per test
10 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Professor GukiZ was playing with arrays again and accidentally discovered new function, which he called GukiZiana. For given array a, indexed with integers from 1 to n, and number yGukiZiana(a, y) represents maximum value of j - i, such that aj = ai = y. If there is no y as an element in a, then GukiZiana(a, y) is equal to  - 1. GukiZ also prepared a problem for you. This time, you have two types of queries:

  1. First type has form 1 l r x and asks you to increase values of all ai such that l ≤ i ≤ r by the non-negative integer x.
  2. Second type has form 2 y and asks you to find value of GukiZiana(a, y).

For each query of type 2, print the answer and make GukiZ happy!

Input

The first line contains two integers nq (1 ≤ n ≤ 5 * 105, 1 ≤ q ≤ 5 * 104), size of array a, and the number of queries.

The second line contains n integers a1, a2, ... an (1 ≤ ai ≤ 109), forming an array a.

Each of next q lines contain either four or two numbers, as described in statement:

If line starts with 1, then the query looks like 1 l r x (1 ≤ l ≤ r ≤ n0 ≤ x ≤ 109), first type query.

If line starts with 2, then th query looks like 2 y (1 ≤ y ≤ 109), second type query.

Output

For each query of type 2, print the value of GukiZiana(a, y), for y value for that query.

Sample test(s)
input
4 3
1 2 3 4
1 1 2 1
1 1 1 1
2 3
output
2
题意:给出n个数字的序列,和q次操作,有两种操作,第一种是[l,r]区间所有数加x,第二种是询问值为y的数最大间隔多少
思路:以为是线段树想不出怎么求解,看了题解后发现不是线段树,不过用来线段树的lazy思想,只不过不用push_down而已。首先你需要把n个数字划分成all=(int)sqrt(n)块,每块ever=n/all个,如果n不能整除all,则all++。你需要保证每一块里的值是递增的,即需要按照值从小到大排序,位置从小到大排序。当你执行更新操作时,你只需要把完全包含的块lazy值+x,这里lazy值我用val数组代替,部分包含的你只需要枚举那一块的所有数,看其下标是否在更新范围内,更新完后,对这些部分包含的块重新递增排序。 查询的时候,你需要从编号最小的块开始枚举,枚举的时候二分查找值为y-val[i]的数,其坐标最小的那个,第一次找到的数即是最小的,然后再从最后一块往前找,二分查找 y-val[i]的数,坐标最大的那个。
注意:这里很多地方都要改成LL,像数组,函数,排序
#pragma comment(linker, "/STACK:1024000000,1024000000") 
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stdlib.h>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<string>
#include<cmath>
#include<iostream>
using namespace std;

#define LL long long
#define ULL unsigned long long

struct sw{
    LL s;
    int loc;
}num[500005],hehe;
int n,q;
int c;
int ever,all;
LL val[500005];

int cmp(const void *a,const void *b){
    if(((sw *)a)->s!=((sw *)b)->s)
        return ((sw *)a)->s-((sw *)b)->s>0?1:-1;
    else return ((sw *)a)->loc-((sw *)b)->loc;
}
int low(int l,int r,LL x){
    while(l<=r){
        int mid = (l+r)>>1;
        if(num[mid].s>=x) r=mid-1;
        else l=mid+1;
    }
    return l;
}
int up(int l,int r,LL x){
    while(l<=r){
        int mid = (l+r)>>1;
        if(num[mid].s>x) r=mid-1;
        else l=mid+1;
    }
    return l-1;
}
void built(){
    for(int i=1;i<=all;i++){
        int l = (i-1)*ever+1;
        int r = min(ever*i,n);
        qsort(num+l,r-l+1,sizeof(num[0]),cmp);
    }
}
void update(int l,int r,LL x){
    int s = ((l-1)/ever)+1;
    int e = ((r-1)/ever)+1;
    for(int i=s+1;i<e;i++) val[i]+=x;
    int ll = (s-1)*ever+1;
    int rr = min(ever*s,n);
    for(int i=ll;i<=rr;i++)
        if(num[i].loc>=l&&num[i].loc<=r){
            num[i].s+=x;
        }
    qsort(num+ll,rr-ll+1,sizeof(num[0]),cmp);
    if(s==e) return;
    ll = (e-1)*ever+1;
    rr = min(ever*e,n);
    for(int i=ll;i<=rr;i++)
        if(num[i].loc>=l&&num[i].loc<=r){
            num[i].s+=x;
        }
    qsort(num+ll,rr-ll+1,sizeof(num[0]),cmp);
}
int query(LL x){
    int ans1=-1,ans2=-1;
    for(int i=1;i<=all;i++){
        int l = (i-1)*ever+1;
        int r = min(i*ever,n);
        int now = low(l,r,x-val[i]);
        if(now>=l&&now<=r&&num[now].s==x-val[i]){
            ans1=num[now].loc;
            break;
        }
    }
    for(int i=all;i>=1;i--){
        int l = (i-1)*ever+1;
        int r = min(i*ever,n);
        int now = up(l,r,x-val[i]);
        if(now>=l&&now<=r&&num[now].s==x-val[i]){
            ans2=num[now].loc;
            break;
        }
    }
    if(ans1==-1&&ans2==-1) return -1;
    else return ans2-ans1;
}
int main(void){
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++){
        int t;
        scanf("%d",&t);
        num[i].s=t;
        num[i].loc=i;
    }
    all = (int)sqrt(n);
    ever = n/all;
    if(all*ever<n) all++;
    built();
    for(int i=1;i<=q;i++){
        int l,r;
        LL x;
        scanf("%d",&c);
        if(c==1){
            scanf("%d%d%I64d",&l,&r,&x);
            update(l,r,x);
        }
        else {
            scanf("%I64d",&x);
            printf("%d\n",query(x));
        }
    }
    
    return 0;
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值