Codeforces Round #670(Div.2) 문제 해결

54862 단어 시합

A


간단한 욕심은 바로 코드에 들어간다.
#include 
#include 
#include 
#include 
using namespace std;
#define maxn 110

int T,n,a[maxn],b[maxn];

int main()
{
     
	scanf("%d",&T);while(T--)
	{
     
		scanf("%d",&n);
		memset(b,0,sizeof(b));
		for(int i=1;i<=n;i++)scanf("%d",&a[i]),b[a[i]]++;
		int ans=0,now=0;
		while(b[now]>1)ans+=2,now++;
		while(b[now]>0)ans++,now++;
		printf("%d
"
,ans); } }

B


mi[i],ma[i]mi[i],ma[i]mi[i],ma[i]는 현재 위치까지 일일이 열거하고 ii의 개수로 곱할 수 있는 최소와 최대 수를 나타낸다. 그들의 이동은 mi[i-1],ma[i-1]mi[i-1],ma[i-1]mi[i-1],ma[i-1],ma[i-1]와 관련되어 마구잡이로 하면 된다.
코드는 다음과 같습니다.
#include 
#include 
#include 
#include 
using namespace std;
#define maxn 200010
#define ll long long

int T,n;
ll a[maxn],mi[10],ma[10];

int main()
{
     
	scanf("%d",&T);while(T--)
	{
     
		scanf("%d",&n);ll ans=-1e18;
		for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
		for(int i=1;i<=5;i++)mi[i]=1e18,ma[i]=-1e18;
		for(int i=1;i<=n;i++){
     
			for(int j=5;j>=2;j--)if(i>=j){
     
				mi[j]=min(mi[j],min(mi[j-1]*a[i],ma[j-1]*a[i]));
				ma[j]=max(ma[j],max(mi[j-1]*a[i],ma[j-1]*a[i]));
			}
			mi[1]=min(mi[1],a[i]);
			ma[1]=max(ma[1],a[i]);
			ans=max(ans,ma[5]);
		}
		printf("%lld
"
,ans); } }

C


처음에 몇 개의 중심을 살펴보고 두 개가 있다면 그 중 한 개의 중심의 한 잎을 다른 중심에 주면 중심이 유일한 것이다.
코드는 다음과 같습니다.
#include 
#include 
#include 
#include 
using namespace std;
#define maxn 200010
#define pb push_back

int T,n;
vector<int>e[maxn];
int size[maxn],mson[maxn],rt,rt_;
void dfs(int x,int fa){
     
	size[x]=1;mson[x]=0;
	for(int y:e[x])if(y!=fa){
     
		dfs(y,x);size[x]+=size[y];
		if(size[y]>mson[x])mson[x]=size[y];
	}
	if(n-size[x]>mson[x])mson[x]=n-size[x];
	if(mson[x]<mson[rt])rt=x,rt_=0;
	else if(mson[x]==mson[rt])rt_=x;
}
void dfs1(int x,int fa,int &l,int &f){
     
	int son=e[x].size()-1;
	if(!son)l=x,f=fa;
	else if(e[x][0]!=fa)dfs1(e[x][0],x,l,f);
	else dfs1(e[x][1],x,l,f);
}

int main()
{
     
	scanf("%d",&T);while(T--)
	{
     
		scanf("%d",&n);
		for(int i=1;i<=n;i++)e[i].clear();
		for(int i=1,x,y;i<n;i++)scanf("%d %d",&x,&y),e[x].pb(y),e[y].pb(x);
		mson[rt=rt_=0]=1e9;dfs(1,0);
		if(rt_){
     
			int l,f;
			dfs1(rt,rt_,l,f);
			printf("%d %d
%d %d
"
,l,f,l,rt_); }else{ printf("%d %d
%d %d
"
,1,e[1][0],1,e[1][0]); } } }

D


먼저 하나의 서열을 어떻게 하강하지 않고 상승하지 않는 서열로 분해할 것인가를 고려해라.감법만 해서 이 서열을 상승하지 않는 서열로 바꾸는 것을 고려하면, 최대치가 이전 서열의 최소치와 같을 때까지 모든 극장 불하강 서브 세그먼트를 전체적으로 줄여야 한다.
그러면 각 위치에서 뺀 값은 반드시 내려가지 않는 서열을 형성할 수 있고 두 서열은 구조가 끝난다.그리고 그들의 최대치를 최소화해야 한다. a, b, a, b는 두 서열의 현재 최대치이다. 분명히 큰 것은 전체적으로 줄이고 작은 것은 전체적으로 증가하며 최대치는\lceil\rac {a+b} 2\rceil\2a+b⌉이다.
상승하지 않는 서열의 최대치는 분명히 첫 번째 서열의 수이고 하락하지 않는 서열의 최대치는 이 서열의 마지막 서열의 수이다. 원래의 서열을 bb수조로 나누면 마지막 서열의 수는 모두 b[i]>0b[i]>0b[i]>0의 b[i]b[i]b[i]b[i]b[i]의 합을 만족시키는 것이다.
수정하면 바로 차점수 그룹을 수정하여 O(1)O(1)O(1)완성할 수 있습니다.
코드는 다음과 같습니다.
#include 
#include 
#include 
#include 
using namespace std;
#define maxn 100010
#define ll long long

int n,m;
ll a[maxn],b[maxn],sum=0;

int main()
{
     
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%lld",&a[i]),b[i]=a[i]-a[i-1];
	for(int i=2;i<=n;i++)if(b[i]>0)sum+=b[i];
	printf("%lld
"
,(ll)ceil(1.0*(b[1]+sum)/2.0)); scanf("%d",&m); for(int i=1,l,r,x;i<=m;i++){ scanf("%d %d %d",&l,&r,&x); if(l>1&&b[l]>0)sum-=b[l]; b[l]+=x; if(l>1&&b[l]>0)sum+=b[l]; if(r<n){ r++; if(b[r]>0)sum-=b[r]; b[r]-=x; if(b[r]>0)sum+=b[r]; } printf("%lld
"
,(ll)ceil(1.0*(b[1]+sum)/2.0)); } }

E


10510^5 105 이내의 질량수가 9592 9592 9592개라는 것을 발견하였는데, 이는 각 질량수가 약 11번만 조작할 수 있음을 의미한다.
먼저 n\sqrtn 이내의 질수를 매거하고, xx질인수를 분해한 후 이 질수의 출현 횟수는 111을 초과할 수 있으며, 매번 폭력 BBB가 매거한 pppp를 매거한 다음에 p,p2,p3을 매거한다.p,p^2,p^3,... p,p2,p3,... 차례대로 A A 조작을 하면 그들의 출현 횟수를 확정할 수 있다.
다시 n\sqrtnn보다 큰 질수를 고려하면 이 질수는 가장 많이 한 번 나타나고 이때 n\sqrtn~nn 범위 내에 합수가 없다(xxx 제외).
먼저 xxx는 n\sqrtn보다 큰 질수이고 매번 BBB의 반수를 고려한다. 만약에 BB가 끝난 후에 A1A~1A1에게 물어보면 예상한 것과 다르다. 그러면 이 중에는 반드시 xxx가 있다. 각 AA는 한 번에 찾을 수 있다. 그렇지 않으면 다른 반에서 위의 조작을 반복하면 이런 조작에 필요한 횟수가 대략 회라는 것을 알 수 있다.
다시 xxx가 n\sqrtn보다 큰 질수를 인자로 가지고 있으나 질수가 아닌 경우를 고려하면 위에서 BBB를 가지는 과정에서 어떤 BB가 222를 냈는지 확인해 보면 된다.
코드는 다음과 같습니다.
#include 
#include 
#include 
#include 
using namespace std;
#define maxn 100010

int n,ans=1;
int prime[maxn],t=0;
bool v[maxn];
void work(){
     
	for(int i=2;i<=n;i++){
     
		if(!v[i])prime[++t]=i;
		for(int j=1;j<=t&&i*prime[j]<=n;j++){
     
			v[i*prime[j]]=true;
			if(i%prime[j]==0)break;
		}
	}
}
int ask(char x,int y){
     
	printf("%c %d
"
,x,y);fflush(stdout); if(x!='C'){ int re;scanf("%d",&re);return re;} else exit(0); } int st=1,sum; void solve(int l,int r){ int mid=l+r>>1; for(int i=l;i<=mid;i++){ if(ask('B',prime[i])>1)ask('C',ans*prime[i]); sum--; } if(ask('A',1)!=sum){ for(int i=l;i<=mid;i++) if(ask('A',prime[i]))ask('C',ans*prime[i]); } if(mid<r)solve(mid+1,r); } int main() { scanf("%d",&n);work();sum=n; for(;st<=t&&prime[st]*prime[st]<=n;st++){ int &x=prime[st]; sum-=ask('B',x); if(ask('A',1)!=sum){ sum++; for(int j=x;j<=n&&ask('A',j);j*=x)ans*=x; } } if(st<=t)solve(st,t); ask('C',ans); }

좋은 웹페이지 즐겨찾기