1. 程式人生 > 其它 >AtCoder Beginner Contest 207

AtCoder Beginner Contest 207

A
排序後模擬即可。

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define ll long long
#define db double
#define N 20000
#define mod 1000000007
#define eps (1e-7)
#define U unsigned int
#define IT set<ques>::iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
using namespace std;
int a[3];
int main(){
	scanf("%d%d%d",&a[0],&a[1],&a[2]);sort(a,a+3);printf("%d\n",a[2]+a[1]);
} 

B
\(t\)為次數,那麼就是要求最小的\(t\)使得\(A+Bt\leq CDt\)
移項得到\(t(CD-B)\geq A\)
此時如果\(CD\leq B\)顯然無解,否則上取整即可。
code:

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define ll long long
#define db double
#define N 20000
#define mod 1000000007
#define eps (1e-7)
#define U unsigned int
#define IT set<ques>::iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
using namespace std;
ll A,B,C,D;
int main(){
	scanf("%lld%lld%lld%lld",&A,&B,&C,&D);
	if(C*D-B<=0)printf("-1\n");
	else printf("%lld\n",(ll)ceil(A*1.0/(C*D-B)));
} 

[C](https://atcoder.jp/contests/abc207/tasks/abc207_c)
我們可以將開區間設為減去\(eps\)的閉區間。
那麼暴力列舉判斷即可。
code:

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define ll long long
#define db double
#define N 2000
#define mod 1000000007
#define eps (1e-7)
#define U unsigned int
#define IT set<ques>::iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
using namespace std;
int n,m,ans,t;db A[N+5],B[N+5];
int main(){
	re int i,j;scanf("%d",&n);for(i=1;i<=n;i++) scanf("%d%lf%lf",&t,&A[i],&B[i]),(t==2)&&(B[i]-=eps),(t==3)&&(A[i]+=eps),(t==4)&&(B[i]-=eps,A[i]+=eps);
	for(i=1;i<=n;i++){
		for(j=i+1;j<=n;j++) ans+=(max(A[i],A[j])<=min(B[i],B[j]));
	}printf("%d\n",ans);
} 

D
我這道題解法大概不是正解。
首先考慮兩個點集怎麼判斷是否匹配。
我們將兩個點集按照\(x\)排序,相同按\(y\)排序,然後一一對應看看是不是都小於\(eps\)即可。
然後我們列舉\(i\)每次讓\(i\)加上一個小的弧度,然後旋轉出第一個點集然後用上面的方法判斷即可。
調一下參就能過去。
code:

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define ll long long
#define db double
#define N 100
#define mod 1000000007
#define eps (1e-5)
#define U unsigned int
#define IT set<ques>::iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
using namespace std;
int n,A[N+5],B[N+5],flag;db nowx,nowy;
struct point{db A,B;}S[N+5],C[N+5];I bool cmp(point x,point y){return x.A==y.A?(x.B<y.B):(x.A<y.A);}
int main(){
	freopen("1.in","r",stdin);
	re int i,j;scanf("%d",&n);for(i=1;i<=n;i++) scanf("%d%d",&A[i],&B[i]);for(i=1;i<=n;i++) scanf("%lf%lf",&C[i].A,&C[i].B);sort(C+1,C+n+1,cmp);
	for(db i=0;i<=360;i+=(5e-4)){nowx=cos(i);nowy=sin(i);
		for(j=1;j<=n;j++) S[j].A=A[j]*nowx-B[j]*nowy,S[j].B=A[j]*nowy+B[j]*nowx;sort(S+1,S+n+1,cmp);
		flag=0;nowx=S[1].A-C[1].A;nowy=S[1].B-C[1].B;for(j=2;j<=n;j++) if(abs(S[j].A-C[j].A-nowx)>eps||abs(S[j].B-C[j].B-nowy)>eps){flag=1;break;} 
		if(!flag){printf("Yes\n");return 0;}
	}printf("No\n");
}

E
這道題大概是這場比賽中最妙的題目。
首先我們設\(dp_{i,j}\)表示到了第\(i\)個,已經劃分了\(j\)段,暴力列舉前面看看能不能轉移,這個是\(O(n^3)\)的。
考慮換一個列舉順序,首先列舉\(j\),再列舉\(i\),一個區間\([l,r]\)能夠被整除的充要條件是\(Sum_{l-1}\equiv Sum_{r}\pmod j\)
那麼我們可以對於同餘記錄,這樣就可以\(O(n^2)\)轉移了。
code:

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define ll long long
#define db double
#define N 3000
#define mod 1000000007
#define eps (1e-7)
#define U unsigned int
#define IT set<ques>::iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
using namespace std;
int n;ll A[N+5],dp[N+5][N+5],Sum[N+5],G[N+5],Ans;
int main(){
	freopen("1.in","r",stdin);
	re int i,j;scanf("%d",&n);for(i=1;i<=n;i++)scanf("%lld",&A[i]),Sum[i]=Sum[i-1]+A[i];
	for(i=1;i<=n;i++){
		memset(G,0,sizeof(G));if(i==1)G[0]=1;for(j=1;j<=n;j++)
		dp[j][i]=G[Sum[j]%i],G[Sum[j]%i]=(dp[j][i-1]+G[Sum[j]%i])%mod; 
	}
	for(i=1;i<=n;i++)Ans+=dp[n][i];printf("%lld\n",Ans%mod);
} 

F
看到這種題容易想到樹形dp
\(dp_{i,j,0/1/2}\)表示\(i\)子樹內有\(j\)個被覆蓋到且當前點未被選擇且不受子樹影響/已被選擇/未被選擇但受子樹影響
然後隨便轉移。注意實現的細節使得這個複雜度是\(O(n^2)\)的。
code:

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define ll long long
#define db double
#define N 3000
#define mod 1000000007
#define eps (1e-7)
#define U unsigned int
#define IT set<ques>::iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
using namespace std;
int n,x,y,siz[N+5],in[N+5];ll dp[N+5][N+5][3];
struct yyy{int to,z;};
struct ljb{int head,h[N+5];yyy f[N+5<<1];I void add(int x,int y){f[++head]=(yyy){y,h[x]};h[x]=head;}}s;
I void dfs(int x,int last){
	siz[x]=dp[x][0][0]=dp[x][1][1]=1;yyy tmp;re int i,j,h;for(i=s.h[x];i;i=tmp.z){
		tmp=s.f[i];if(tmp.to==last) continue;dfs(tmp.to,x);for(j=0;j<=siz[tmp.to];j++) dp[tmp.to][j][0]%=mod,dp[tmp.to][j][1]%=mod,dp[tmp.to][j][2]%=mod;;
		for(j=siz[x];~j;j--){dp[x][j][0]%=mod;dp[x][j][1]%=mod;dp[x][j][2]%=mod;
			for(h=siz[tmp.to];~h;h--){
				if(h)dp[x][j+h][0]+=dp[x][j][0]*(dp[tmp.to][h][0]+dp[tmp.to][h][2])%mod;
				if(h)dp[x][j+h][1]+=dp[x][j][1]*(dp[tmp.to][h][1]+dp[tmp.to][h][2])%mod;
				dp[x][j+h+1][1]+=dp[x][j][1]*dp[tmp.to][h][0]%mod;
				if(h)dp[x][j+h][2]+=dp[x][j][2]*(dp[tmp.to][h][1]+dp[tmp.to][h][0]+dp[tmp.to][h][2])%mod;
				dp[x][j+h+1][2]+=(dp[x][j][0]*dp[tmp.to][h][1])%mod;
			}dp[x][j][1]=0;
		} siz[x]+=siz[tmp.to];
	}
}
int main(){
	freopen("1.in","r",stdin);
	re int i;scanf("%d",&n);for(i=1;i<n;i++) scanf("%d%d",&x,&y),s.add(x,y),s.add(y,x),in[x]++,in[y]++;
	dfs(1,0);for(i=0;i<=n;i++) printf("%lld\n",(dp[1][i][0]+dp[1][i][1]+dp[1][i][2])%mod);
}