codeforces good bye 2018

codeforces good bye 2018

good bye candidate master

2018年的最后一场cf

感觉打完我又用rating换了一大波rp

T1

题意: 给出三个数\(r\)\(b\)\(y\),定义\(a\)\(b\)\(c\)是分别小于等于这三个数且满足\(a+2==b+1=c\)

\(a+b+c\)的最大值

题解: 日常读错题,zz的我考场上没看清楚题面以为是要求\(a>b>c\),样例没测就交了。。。WA*1

实际上只要枚举一下\(a\)\(b\)\(c\)那个取了最大值就好了,,,要满足答案最大,一定有一个是取最大值的

代码:

#include<map>
#include<queue>
#include<cmath>
#include<bitset>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int a,b,c;
int main(){
//	freopen("1.in","r",stdin);
	scanf("%d%d%d",&a,&b,&c);
	if(a+1<=b&&a+2<=c) printf("%d\n",3*a+3);
	else
	if(b<=a+1&&b+1<=c) printf("%d\n",3*b);
	else
	printf("%d\n",3*c-3);
	return 0;
}

T2

题意:给出\(n\)个标志物坐标\((x_i,y_i)\)以及\(n\)个线索\((a_i,b_i)\),要把标志物和线索两两匹配使得所有\((x_i+a[p_i],y_i+a[y_i])\)相等

题解:本来是想要先枚举第一个坐标所匹配的线索,然后判断是否存在匹配方案使得宝藏坐标等于枚举出的坐标,这样时间复杂度\(n^2logn\)应该也能过,虽然有点zz

然而其实这道题可以\(nlogn\)过:要想每个都相等,对于最小的\(x\)坐标,一定要给他最大的\(a\)来补,对于\(y\)也是一样。。

这样的话sort一遍就好了

代码:

#include<map>
#include<queue>
#include<cmath>
#include<bitset>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=1100;
struct node{
	int x,y;
}e[maxn],t[maxn];
int n;
bool cmp(node x,node y){return x.x<y.x;}
bool Cmp(node x,node y){return x.y<y.y;}
int main(){
//	freopen("1.in","r",stdin);
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d%d",&e[i].x,&e[i].y);
	for(int i=1;i<=n;i++)
		scanf("%d%d",&t[i].x,&t[i].y);
	sort(e+1,e+n+1,cmp);
	sort(t+1,t+n+1,cmp);
	printf("%d ",e[1].x+t[n].x);
	sort(e+1,e+n+1,Cmp);
	sort(t+1,t+n+1,Cmp);
	printf("%d\n",e[1].y+t[n].y);
	return 0;
}

T3

题意:n个元素的环,编号为1~n,一个球一开始在1,每次可以顺时针移动k步,每移动到一个点上就会产生这个点的编号点贡献,再次到1时停止,问对于所有k,能产生哪几种不同的总贡献

题解:对于n的每一个约数都统计一下就好了,不要忘记去重

代码:

#include<map>
#include<queue>
#include<cmath>
#include<bitset>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=1e7+100;
int n,tot;
ll p[maxn];
inline int work(int n,int x){
	ll tmp=n/x;
	p[++tot]=n*(tmp-1)/2+tmp;
}
int main(){
//	freopen("1.in","r",stdin);
	scanf("%d",&n);
	for(int i=1;i*i<=n;i++)
		if(n%i==0){
			work(n,i),work(n,n/i); 
		}
	sort(p+1,p+tot+1);p[0]=-1;
	for(int i=1;i<=tot;i++)
		if(p[i]!=p[i-1]) printf("%I64d ",p[i]);
	printf("\n");
	return 0;
}

T4

题意:把n个元素的所有排列按字典序头尾相接,形成一个长为\(n*n!\)的数列a,问有多少对\(l,r\)满足

\[a[l]+a[l+1]+...+a[r-1]+a[r]=n*(n+1)/2 \]

题解:分析了一下样例,很显然的可以发现只有当\(l,r\)代表的是一个排列的时候才会等于\(n*(n+1)/2\),就考虑对于每个排列,他对答案的贡献

想象对于每个答案排列,他都可以分为两部分,一部分属于\(a\)中的前一个排列末尾,一个属于后一个排列开头,因为排列总数是\(n!\),对于一个排列分法有\(n\)种,所以总方案应是\(n*n!\)

但是这些方案中有一些是不合法的,比如:(n=5,设\(x\)是前一个末尾,y是后一个开头)

\[x=\{4,2\},y=\{1,3,5\} \]

显然,完整的前一个应该是\(\{1,3,5,4,2\}\),但是我们发现,后一个是不会合法的,因为他要满足比前一个大,但是前一个的最后两位(即\(x\))是单减的,也就是说没有比\(x\)大的了。

那么我们枚举所有长度的单减序列,长度为\(i\)的单减序列总数就等于在一个\(\{n,n-1,n-2,...,1\}\)的序列里挑\(i\)个数,即\(C(n,i)\),对于每个单减序列\(x\),他的\(y\)是可以随便填的(这里的x,y还是上面的定义),方案总数\((n-i)!\)

然后就没有然后了,总方案数\(n*n!\),不合法方案数\(\sum_{i=1}^n{C(n,i)*(n-i)!}\),合法方案就是:

\[ans=n*n!-\sum_{i=1}^n{C(n,i)*(n-i)!} \]

如果你没有和zz的nianheng一样在手算时zz地把\(4!\)算成\(16\),你就能马上A掉这道题了

代码:

#include<map>
#include<queue>
#include<cmath>
#include<bitset>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=1e7+100,P=998244353;
int n;
ll jc[maxn],ans;
void ycl(){
	jc[0]=1;
	for(int i=1;i<=n;i++)
		jc[i]=jc[i-1]*i%P;
}
inline ll poww(ll x,ll y){
	ll base=1;
	while(y){
		if(y&1) base=base*x%P;
		x=x*x%P;
		y>>=1;
	}
	return base;
}
inline ll C(int n,int m){
	return jc[n]*poww(jc[m],P-2)%P*poww(jc[n-m],P-2)%P;
}
int main(){
//	freopen("1.in","r",stdin);
	scanf("%d",&n);
	ycl();
	for(int i=1;i<=n;i++)
		ans=(ans+C(n,i)*jc[n-i]%P)%P;
	ans=(jc[n]*n%P-ans)%P;
	printf("%I64d\n",(ans+1)%P);
	return 0;
}

感想

失误辣么多,我还是太蒻了啊

posted @ 2018-12-31 02:18  nianheng  阅读(259)  评论(0编辑  收藏  举报