AtCoder Grand Contest 001

A

很明显排个序就行了。

#include<bits/stdc++.h>
#define ll long long
#define gc getchar
#define pc putchar
#define pii pair<int,int>
#define mp make_pair
#define fi first
#define se second
#define rep(i,x,y) for(int i=x;i<=y;i++)
#define dwn(i,x,y) for(int i=x;i>=y;i--)
#define mod 1000000007
using namespace std;
template<typename T>inline void qr(T &x){
	x=0;int f=0;char s=gc();
	while(s<'0'||'9'<s)f|=s=='-',s=gc();
	while('0'<=s&&s<='9')x=x*10+s-48,s=gc();
	x=f?-x:x;
}
int cc=0,buf[31];
template<typename T>inline void qw(T x){
	if(x<0)putchar('-'),x=-x;
	do{buf[++cc]=int(x%10);x/=10;}while(x);
	while(cc)pc(buf[cc--]+'0');puts("");
}
int ad(int x,int y){return (x+y)>=mod?x+y-mod:x+y;}
int mu(int x,int y){return 1ll*x*y%mod;}
int de(int x,int y){return (x-y)<0?x-y+mod:x-y;}
const int N=1e2+10;
int n,a[N<<1];
void solve(){
	qr(n);
	rep(i,1,n*2)qr(a[i]);
	sort(a+1,a+n*2+1);
	int ret=0;
	rep(i,1,n)ret+=a[2*i-1];
	qw(ret);
}
int main(){
	int tt;tt=1;
	while(tt--)solve();
	return 0;
}

B

一开始瞎猜结论,但是错了。
后面发现可以把路线看成平行四边形,然后用类似gcd的东西来求解。

#include<bits/stdc++.h>
#define ll long long
#define gc getchar
#define pc putchar
#define pii pair<int,int>
#define mp make_pair
#define fi first
#define se second
#define rep(i,x,y) for(int i=x;i<=y;i++)
#define dwn(i,x,y) for(int i=x;i>=y;i--)
#define mod 1000000007
using namespace std;
template<typename T>inline void qr(T &x){
	x=0;int f=0;char s=gc();
	while(s<'0'||'9'<s)f|=s=='-',s=gc();
	while('0'<=s&&s<='9')x=x*10+s-48,s=gc();
	x=f?-x:x;
}
int cc=0,buf[31];
template<typename T>inline void qw(T x){
	if(x<0)putchar('-'),x=-x;
	do{buf[++cc]=int(x%10);x/=10;}while(x);
	while(cc)pc(buf[cc--]+'0');puts("");
}
int ad(int x,int y){return (x+y)>=mod?x+y-mod:x+y;}
int mu(int x,int y){return 1ll*x*y%mod;}
int de(int x,int y){return (x-y)<0?x-y+mod:x-y;}
ll calc(ll x,ll y){
	if(x%y==0)return (2ll*x/y-1)*y;
	if(y%x==0)return (2ll*y/x-1)*x;
	if(x<y)return 2ll*(y/x)*x+calc(x,y%x);
	if(x>y)return 2ll*(x/y)*y+calc(x%y,y);
}
void solve(){
	ll n,x;qr(n),qr(x);
	qw(n+calc(x,n-x));
}
int main(){
	int tt;tt=1;
	while(tt--)solve();
	return 0;
}

C

先试了两种错误的做法,分别是树形dp(必须要根节点不被删除),和在直径上面截取k的路径(貌似是对的,实际上是错的)。
最后膜了一波题解。发现原来树的直径也能够像在圆上面一样!所以只用枚举一下点(k是偶数)或者边(k是奇数),然后统计一下,取最小值。

#include<bits/stdc++.h>
#define ll long long
#define gc getchar
#define pc putchar
#define pii pair<int,int>
#define mp make_pair
#define fi first
#define se second
#define rep(i,x,y) for(int i=x;i<=y;i++)
#define dwn(i,x,y) for(int i=x;i>=y;i--)
#define mod 1000000007
#define inf 2010
using namespace std;
template<typename T>inline void qr(T &x){
	x=0;int f=0;char s=gc();
	while(s<'0'||'9'<s)f|=s=='-',s=gc();
	while('0'<=s&&s<='9')x=x*10+s-48,s=gc();
	x=f?-x:x;
}
int cc=0,buf[31];
template<typename T>inline void qw(T x){
	if(x<0)putchar('-'),x=-x;
	do{buf[++cc]=int(x%10);x/=10;}while(x);
	while(cc)pc(buf[cc--]+'0');puts("");
}
int ad(int x,int y){return (x+y)>=mod?x+y-mod:x+y;}
int mu(int x,int y){return 1ll*x*y%mod;}
int de(int x,int y){return (x-y)<0?x-y+mod:x-y;}
const int N=2e3+5;
int n,k,fa[N],dep[N];
int tot=1,hd[N],ver[N<<1],nxt[N<<1];
int cnt,a[N];bool v[N];
void add(int x,int y){ver[++tot]=y;nxt[tot]=hd[x];hd[x]=tot;}
int ban1,ban2;
int dfs(int x){
	int ret=(dep[x]>k);
	for(int i=hd[x];i;i=nxt[i]){
		int y=ver[i];if(y==fa[x]||y==ban1||y==ban2)continue;
		fa[y]=x,dep[y]=dep[x]+1,ret+=dfs(y);
	}
	return ret;
}
void solve(){
	qr(n),qr(k);
	rep(i,1,n-1){
		int x,y;qr(x),qr(y);
		add(x,y),add(y,x);
	}
	if(k%2==0){
		int ans=n;k/=2;
		rep(i,1,n)dep[i]=fa[i]=0,ans=min(ans,dfs(i));
		qw(ans);
	}
	else{
		int ans=n;k=k/2;
		for(int i=2;i<=tot;i+=2){
			ban1=ver[i],ban2=ver[i^1];
			fa[ban1]=fa[ban2]=dep[ban1]=dep[ban2]=0;
			ans=min(ans,dfs(ban1)+dfs(ban2));
		}
		qw(ans);
	}
}
int main(){
//	freopen("C.in","r",stdin);
//	freopen("C.out","w",stdout);
	int tt=1;
	while(tt--)solve();
	return 0;
}

D

本来这事一道很sb的题,但是我因为犯了两个弱智错误而浪费了很多错误。
我们将长度分为奇数和偶数两种情况来讨论:
1.奇数:在把全部连起来以后还能多出一个空位;
2.偶数:把全部连起来以后还能多出两个空位;
然后手玩一下,发现奇数最多会有两个,然后直接处理即可。

#include<bits/stdc++.h>
#define ll long long
#define gc getchar
#define pc putchar
#define pii pair<int,int>
#define mp make_pair
#define fi first
#define se second
#define rep(i,x,y) for(int i=x;i<=y;i++)
#define dwn(i,x,y) for(int i=x;i>=y;i--)
#define mod 1000000007
#define inf 2010
using namespace std;
template<typename T>inline void qr(T &x){
	x=0;int f=0;char s=gc();
	while(s<'0'||'9'<s)f|=s=='-',s=gc();
	while('0'<=s&&s<='9')x=x*10+s-48,s=gc();
	x=f?-x:x;
}
int cc=0,buf[31];
template<typename T>inline void qw(T x){
	if(x<0)putchar('-'),x=-x;
	do{buf[++cc]=int(x%10);x/=10;}while(x);
	while(cc)pc(buf[cc--]+'0');pc(' ');
}
const int N=1e2+10,M=1e5+10;
int m,n,a[N],b[N],siz,ans[N];
void ins(int x){if(x)ans[++siz]=x;}
void solve(){
	qr(m),qr(n);
	int s[2]={0,0};
	rep(i,1,n)qr(a[i]),s[a[i]&1]++;
	if(s[1]<=2){
		int cnt=0;
		rep(i,1,n)if(a[i]&1)b[++cnt]=a[i];
		rep(i,1,n)if(!(a[i]&1)){
			if(s[1]==2)b[cnt+1]=b[cnt],b[cnt]=a[i],cnt++;
			else b[++cnt]=a[i];
		}
		if(!s[1]){
			rep(i,1,n)qw(b[i]);puts("");
			ins(b[1]-2);ins(1);
			rep(i,2,n)ins(b[i]);
			ins(1);
		}
		else if(s[1]==1){
			rep(i,1,n)qw(b[i]);puts("");
			ins(b[1]-1);
			rep(i,2,n)ins(b[i]);
			ins(1);
		}
		else{
			rep(i,1,n)qw(b[i]);puts("");
			ins(b[1]-1);
			rep(i,2,n-1)ins(b[i]);
			ins(b[n]+1);
		}
		qw(siz);puts("");
		rep(i,1,siz)qw(ans[i]);puts("");
	}
	else puts("Impossible");
}
int main(){
//	freopen("D.in","r",stdin);
//	freopen("D.out","w",stdout);
	int tt;tt=1;
	while(tt--)solve();
	return 0;
}

E

题意就是求: ∑ i = 1 n ∑ j = i + 1 n C a [ i ] + b [ i ] + a [ j ] + b [ j ] a [ i ] + a [ j ] \sum_{i=1}^n\sum_{j=i+1}^nC_{a[i]+b[i]+a[j]+b[j]}^{a[i]+a[j]} i=1nj=i+1nCa[i]+b[i]+a[j]+b[j]a[i]+a[j]

一开始我试了几种思路都是错的,主要是因为无法利用好组合数的性质,都必须要把组合数求出来。

所以我们要找到一种方法能够避免把每种组合数都算出来。

可以发现,这个计数很像网格图中矩形从左下角走到右上角只能往右或者往上的方案数。所以我们将 ( 2000 , 2000 ) (2000,2000) (2000,2000)设置为原点。然后对于每一个点,将 f [ 2000 − a [ i ] ] [ 2000 − b [ i ] ] + + f[2000-a[i]][2000-b[i]]++ f[2000a[i]][2000b[i]]++,然后dp一下,求出来的每一个点的方案数以后减去自己对自己的贡献最后除以2即可。

#include<bits/stdc++.h>
#define ll long long
#define gc getchar
#define pc putchar
#define pii pair<int,int>
#define mp make_pair
#define fi first
#define se second
#define rep(i,x,y) for(int i=x;i<=y;i++)
#define dwn(i,x,y) for(int i=x;i>=y;i--)
#define mod 1000000007
#define inf 2010
using namespace std;
template<typename T>inline void qr(T &x){
  x=0;int f=0;char s=gc();
  while(!isdigit(s))f|=s=='-',s=gc();
  while(isdigit(s))x=x*10+s-48,s=gc();
  x=f?-x:x;
}
int cc,buf[31];
template<typename T>inline void qw(T x){
  if(x<0)pc('-'),x=-x;
  do{buf[++cc]=int(x%10);x/=10;}while(x);
  while(cc)pc(buf[cc--]+'0');pc(' ');
}
int ad(int x,int y){return (x+y)>=mod?x+y-mod:x+y;}
int mu(int x,int y){return 1ll*x*y%mod;}
int de(int x,int y){return (x-y)<0?x-y+mod:x-y;}
const int N=2e5+10,M=4e3+10,key=2e3,L=8e3;
int n,a[N],b[N],f[M][M],fac[L+5],inv[L+5];
int power(int a,int b){
  int ret=1;
  while(b){
    if(b&1)ret=mu(ret,a);
    a=mu(a,a);b>>=1;
  }
  return ret;
}
int C(int n,int m){
  if(n<0||m<0||n<m)return 0;
  return mu(fac[n],mu(inv[m],inv[n-m]));
}
int main(){
  qr(n);
  rep(i,1,n)qr(a[i]),qr(b[i]),f[key-a[i]][key-b[i]]++;
  rep(i,0,key*2)rep(j,0,key*2){
    if(i)f[i][j]=ad(f[i][j],f[i-1][j]);
    if(j)f[i][j]=ad(f[i][j],f[i][j-1]);
  }
  fac[0]=1;rep(i,1,L)fac[i]=mu(i,fac[i-1]);
  inv[L]=power(fac[L],mod-2);dwn(i,L-1,0)inv[i]=mu(inv[i+1],i+1);
  int ans=0;
  rep(i,1,n)ans=de(ad(ans,f[key+a[i]][key+b[i]]),C(a[i]+a[i]+b[i]+b[i],a[i]+a[i]));
  ans=mu(ans,power(2,mod-2));qw(ans);
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值