XV Open Cup named after E.V. Pankratiev. GP of Tatarstan

A. Survival Route

留坑。

B. Dispersed parentheses

$f[i][j][k]$表示长度为$i$,未匹配的左括号数为$j$,最多的未匹配左括号数为$k$的方案数。时间复杂度$O(n^3)$。

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int P=1000000009;
const int N=310;
int n,m,i,j,k,f[N][N][N];
inline void up(int&a,int b){a+=b;if(a>=P)a-=P;}
int main(){
  scanf("%d%d",&n,&m);
  f[0][0][0]=1;
  for(i=1;i<=n;i++)for(j=0;j<=i;j++)for(k=j;k<=m;k++){
    if(f[i-1][j][k]){
      up(f[i][j][k],f[i-1][j][k]);
      up(f[i][j+1][max(j+1,k)],f[i-1][j][k]);
      if(j)up(f[i][j-1][k],f[i-1][j][k]);
    }
  }
  printf("%d",f[n][0][m]);
}

  

C. Chocolate triangles

留坑。

D. LWDB

把树的点分治过程记录下来,每个分治结构按覆盖距离维护一个栈,查询时二分即可。时间复杂度$O(n\log^2n)$。

#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
typedef pair<int,int>P;
typedef pair<int,P>PI;
const int N=100010,M=3000000;
int n,m,i,x,y,z,op;
int g[N],nxt[N<<1],v[N<<1],w[N<<1],ok[N<<1],ed;
int son[N],f[N],all,now,cnt,value[N];
int G[N],NXT[M],V[M],W[M],ED;
vector<PI>q[N];
int top[N];
int Time;
//top dis is low but time is new
inline void add(int x,int y,int z){
  v[++ed]=y;
  w[ed]=z;
  nxt[ed]=g[x];
  ok[ed]=1;
  g[x]=ed;
}
inline void ADD(int x,int y,int w){
  V[++ED]=y;
  W[ED]=w;
  NXT[ED]=G[x];
  G[x]=ED;
}
void findroot(int x,int y){
  son[x]=1,f[x]=0;
  for(int i=g[x];i;i=nxt[i])if(ok[i]&&v[i]!=y){
    findroot(v[i],x);
    son[x]+=son[v[i]];
    if(son[v[i]]>f[x])f[x]=son[v[i]];
  }
  if(all-son[x]>f[x])f[x]=all-son[x];
  if(f[x]<f[now])now=x;
}
void dfs(int x,int y,int dis){
  ADD(x,now,dis);
  for(int i=g[x];i;i=nxt[i])if(ok[i]&&v[i]!=y)dfs(v[i],x,dis+w[i]);
}
void solve(int x){
  int i;
  dfs(x,0,0);
  for(i=g[x];i;i=nxt[i])if(ok[i]){
    ok[i^1]=0;
    f[0]=all=son[v[i]];
    findroot(v[i],now=0);
    solve(now);
  }
}
inline void paint(int x,int y,int z){
  Time++;
  for(int i=G[x];i;i=NXT[i]){
    int w=y-W[i];
    if(w<0)continue;
    int u=V[i];
    while(top[u]){
      if(w>=q[u][top[u]-1].first)top[u]--;
      else break;
    }
    PI t(w,P(Time,z));
    if(top[u]==q[u].size())q[u].push_back(t);else q[u][top[u]]=t;
    top[u]++;
  }
}
inline int query(int x){
  P ret(0,0);
  for(int i=G[x];i;i=NXT[i]){
    int w=W[i];
    int u=V[i];
    if(!top[u])continue;
    if(q[u][0].first<w)continue;
    int l=0,r=top[u]-1,mid,fin;
    while(l<=r){
      mid=(l+r)>>1;
      if(q[u][mid].first>=w)l=(fin=mid)+1;else r=mid-1;
    }
    ret=max(ret,q[u][fin].second);
  }
  return ret.second;
}
int main(){
  scanf("%d",&n);
  for(ed=i=1;i<n;i++){
    scanf("%d%d%d",&x,&y,&z);
    add(x,y,z);
    add(y,x,z);
  }
  f[0]=all=n;
  findroot(1,now=0);
  solve(now);
  scanf("%d",&m);
  while(m--){
    scanf("%d%d",&op,&x);
    if(op==1)scanf("%d%d",&y,&z),paint(x,y,z);
    else printf("%d\n",query(x));
  }
}

  

E. Pea-City

求出凸包之后旋转卡壳。

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
typedef double DB;
const int N=88888;
const DB eps=1e-8,pi=acos(-1);
DB ans;
int n;
struct PT{
  DB x,y;
  PT(DB x=0,DB y=0):x(x),y(y){}
  void input(){scanf("%lf%lf",&x,&y);}
  bool operator<(const PT&p)const{
    if(fabs(x-p.x))return x<p.x;
    return y<p.y;
  }
  void output(){printf("%.10f %.10f\n",x,y);}
}p[N],q[N];
vector<PT>ret;
DB vect(PT p,PT p1,PT p2){
  return (p1.x-p.x)*(p2.y-p.y)-(p1.y-p.y)*(p2.x-p.x);
}
int convex_hull(PT*p,int n,PT*q){
  int i,k,m;
  sort(p,p+n);
  m=0;
  for(i=0;i<n;q[m++]=p[i++])while(m>1&&vect(q[m-2],q[m-1],p[i])<eps)m--;
  k=m;
  for(i=n-2;i>=0;q[m++]=p[i--])while(m>k&&vect(q[m-2],q[m-1],p[i])<eps)m--;
  return --m;
}
PT get(PT p,DB x){
  return PT(p.x*cos(x)-p.y*sin(x),p.x*sin(x)+p.y*cos(x));
}
bool is_ext(int id,PT pp){
  if(vect(p[id],PT(p[id].x+pp.x,p[id].y+pp.y),p[id+1])<-eps)return 0;
  if(vect(p[id],PT(p[id].x+pp.x,p[id].y+pp.y),p[(id-1+n)%n])<-eps)return 0;
  return 1;
}
PT inter(PT p1,PT p2,PT p3,PT p4){
  p2.x+=p1.x;
  p2.y+=p1.y;
  p4.x+=p3.x;
  p4.y+=p3.y;
  DB s=vect(p1,p2,p3),s1=vect(p1,p2,p4);
  DB t=s/(s-s1);
  return PT(p3.x+(p4.x-p3.x)*t,p3.y+(p4.y-p3.y)*t);
}
void solve(){
  int f[4];
  f[1]=f[2]=f[3]=0;
  for(int i=0;i<n;i++){
    f[0]=i;
    PT v[4];
    v[0]=PT(p[i+1].x-p[i].x,p[i+1].y-p[i].y);
    for(int j=1;j<4;j++)for(v[j]=get(v[0],pi/2*j);!is_ext(f[j],v[j]);f[j]=(f[j]+1)%n);
    vector<PT>tmp;
    for(int j=0;j<4;j++)tmp.push_back(inter(p[f[j]],v[j],p[f[(j+1)%4]],v[(j+1)%4]));
    DB tmps=0;
    for(int j=0;j<4;j++)tmps+=vect(tmp[0],tmp[j],tmp[(j+1)%4]);
    tmps=fabs(tmps);
    if(ans>tmps)ans=tmps,ret=tmp;
  }
}
int main(){
  scanf("%d",&n);
  for(int i=0;i<n;i++)p[i].input();
  n=convex_hull(p,n,q);
  for(int i=0;i<n;i++)p[i]=q[i];
  p[n]=p[0];
  ans=1e100;
  solve();
  for(int i=0;i<4;i++)ret[i].output();
  return 0;
}

  

F. Beautiful sums

等价于求约数个数为$n$的最小奇数,$f[i][j]$表示$i$个质因子,约数个数为$j$的最小奇数,然后DP即可。时间复杂度$O(n\log n)$。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int Maxn=100020;
typedef vector<LL>vi;
const double Inf=1e80;
const int mod=1e9+9;
double dp[17][Maxn];
int pre[17][Maxn],pe[17][Maxn];
int n;
vector<int>ys;
vector<int>pri;
bool isp[100];
int powmod(int x,int y){
	int ret=1;
	while(y){
		if(y&1)ret=1LL*ret*x%mod;
		y>>=1;
		x=1LL*x*x%mod;
	}
	return ret;
}
int main(){
	for(int i=2;i<100;i++){
		if(!isp[i])pri.push_back(i);
		for(int j=i+i;j<100;j+=i)isp[j]=1;
	}
	while(scanf("%d",&n)!=EOF){
		if(n==1){puts("1");continue;}
		for(int i=1;i<=n;i++){
			if(n%i==0)ys.push_back(i);
		}
		for(int i=0;i<=16;i++){
			for(int j=1;j<=n;j++)dp[i][j]=Inf;
		}
		dp[0][1]=0;
		for(int i=1;i<=16;i++){
			for(int j=0;j<ys.size();j++){
				int x=ys[j];
				dp[i][x]=Inf;
				for(int k=0;k<=j;k++){
					int y=ys[k];
					if(x%y)continue;
					if(dp[i-1][x/y]+(y-1)*log(pri[i]+.0)<dp[i][x]){
						dp[i][x]=dp[i-1][x/y]+(y-1)*log(pri[i]+.0);
						pre[i][x]=x/y;
						pe[i][x]=y-1;
					}
				}
			}
		}
		vector<int>res;
		int cur=n;
		for(int i=16;i>=1;i--){
			//printf("cur=%d\n",cur);
			if(pe[i][cur]>=1)res.push_back(pe[i][cur]);
			cur=pre[i][cur];
		}
		sort(res.begin(),res.end(),greater<int>());
		int ans=1;
		for(int i=0;i<res.size();i++){
			//printf("res=%d\n",res[i]);
			ans=1LL*ans*powmod(pri[i+1],res[i])%mod;
		}
		printf("%d\n",ans);
	}
}

  

G. Nano alarm-clocks

按题意模拟即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int Maxn=100020;
const LL t0=1000000000000LL,t1=1000000;
int n;
LL x[Maxn];
int main(){
	while(scanf("%d",&n)!=EOF){
		LL ans=5e18;
		LL totsum=0;
		for(int i=1;i<=n;i++){
			LL a,b,c;scanf("%lld%lld%lld",&a,&b,&c);
			x[i]=a*t0+b*t1+c;
			totsum+=x[i];
		}
		sort(x+1,x+n+1);
		LL cur=0;
		LL All=12*t0;
		for(int i=1;i<=n;i++){
			cur+=x[i];
			LL bef=i*x[i]-cur;
			LL aft=(x[i]+All)*(n-i)-(totsum-cur);
			ans=min(ans,bef+aft);
		}
		printf("%lld %lld %lld\n",ans/t0,(ans/t1)%t1,ans%t1);
	}
}

  

H. Lunch

题意有毒,留坑。

I. Accounting Numeral System

二分然后暴力算组合数,注意要用实数。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef vector<LL>vi;
const int Maxn=2020;
LL dp[Maxn][Maxn],sum[Maxn][Maxn];
LL n,m;
int ans[Maxn];
void calsum(int idx){
	for(int i=0;i<=n;i++){
		sum[idx][i]=dp[idx][i];
		if(i)sum[idx][i]+=sum[idx][i-1];
	}
}
LL cal(LL x){
	if(x<m)return 0;
	LL tmp=1;//C(1000,1000)
	if(m+m<=x){
		for(LL i=0;i<m;i++){
			//if(tmp/(i+1)>ned/(x-i)+1)return 0;
			//if((long double)ned*(i+1.)+10<(long double)tmp*(x-i))return 0;
			tmp=tmp*(x-i)/(i+1);
		}
	}
	else{
		for(LL i=x;i>m;i--){
			//printf("tmp%lld\n",tmp);
			//if((long double)ned*(x-i+1)+10<(long double)tmp*(i))return 0;
			tmp=tmp*i/(x-i+1);
		}
	}
	return tmp;
}
bool check(LL x,LL ned){
	if(x<m)return 1;
	LL tmp=1;//C(1000,1000)
	if(m+m<=x){
		for(LL i=0;i<m;i++){
			//if(tmp/(i+1)>ned/(x-i)+1)return 0;
			if((long double)ned*(i+1.)+10<(long double)tmp*(x-i))return 0;
			tmp=tmp*(x-i)/(i+1);
		}
	}
	else{
		for(LL i=x;i>m;i--){
			//printf("tmp%lld\n",tmp);
			if((long double)ned*(x-i+1)+10<(long double)tmp*(i))return 0;
			tmp=tmp*i/(x-i+1);
		}
	}
	//printf("tmp=%lld\n",tmp);
	if(tmp>ned)return 0;
	return 1;
}
LL solve(LL ned){
	LL l=0,r=1e9;
	while(l+1<r){
		LL mid=(l+r)>>1;
		if(check(mid,ned))l=mid;
		else r=mid;
	//	printf("l=%lld r=%lld\n",l,r);
	}
	return l;
}
int main(){
	//n=10000000000000LL;
	//m=2;
	//printf("%lld",cal(4472136LL));
	//solve(7937589951629LL);
	//printf("%d\n",check(n/2,7937589951629LL));
	//m=10;
	///printf("%d\n",check(10,1));
	while(scanf("%lld%lld",&n,&m)!=EOF){
		//solve(n);
		//printf("%d\n",check(7,n));

		int tot=m;
		LL pre=1e9;
		for(int i=1;i<=tot;i++){
			LL tmp=solve(n);
			//printf("tmp=%lld\n",tmp);
			tmp=min(tmp,pre-1);
			pre=tmp;
			n-=cal(tmp);
			printf("%lld%c",tmp,i==tot?‘\n‘:‘ ‘);
			//printf("tmp=%lld n=%lld\n",tmp,n);
			m--;
		}
		//printf("n=%lld\n",n);

	}

}

  

J. Ceizenpok’s formula

将模数分解质因数之后递归计算,然后用CRT合并即可。

#include<cstdio>
typedef long long ll;
ll n,m,x,y,P,B,s[1111111];
ll exgcd(ll a,ll b){
  if(!b)return x=1,y=0,a;
  ll d=exgcd(b,a%b),t=x;
  return x=y,y=t-a/b*y,d;
}
ll rev(ll a,ll P){exgcd(a,P);while(x<0)x+=P;return x%P;}
ll pow(ll a,ll b,ll P){
  ll t=1;
  for(;b;b>>=1LL,a=a*a%P)if(b&1LL)t=t*a%P;
  return t;
}
struct Num{
  ll a,b;
  Num(){a=1,b=0;}
  Num(ll _a,ll _b){a=_a,b=_b;}
  Num operator*(Num x){return Num(a*x.a%P,b+x.b);}
  Num operator/(Num x){return Num(a*rev(x.a,P)%P,b-x.b);}
};
Num cal(ll n){return n?Num(s[n%P]*pow(s[P],n/P,P)%P,n/B)*cal(n/B):Num(1,0);}
void pre(){
  ll i;
  for(i=s[0]=1;i<P;i++)if(i%B)s[i]=s[i-1]*i%P;else s[i]=s[i-1];
  s[P]=s[P-1];
}
ll solve(int _B,int _P){
  B=_B,P=_P;
  pre();
  Num t=cal(n)/cal(m)/cal(n-m);
  return 1LL*t.a*pow(B,t.b,P)%P;
}
ll a[11111],b[11111];int cnt;
void divide(int P){
  for(int i=2;;i++)if(P%i==0){
    int x=1;
    while(P%i==0)P/=i,x*=i;
    a[cnt]=x;
    b[cnt]=solve(i,x);
    cnt++;
    if(P==1)return;
  }
}
ll CRT(int n){
  ll ans=0,P=1;
  for(int i=0;i<n;i++)P*=a[i];
  for(int i=0;i<n;i++)ans=(ans+(P/a[i])*rev(P/a[i],a[i])%P*b[i]%P)%P;
  return (ans%P+P)%P;
}
int main(){
  int P;
  scanf("%lld%lld%d",&n,&m,&P);
  divide(P);
  printf("%lld",CRT(cnt));
}

  

K. Dividing an orange

留坑。

L. The Pool for Lucky Ones

按题意模拟即可。

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
int n,i,a[200000],v[1000000];ll ans=1LL<<60;
void change(int x,int a,int b,int c,int p){
  v[x]+=p;
  if(a==b)return;
  int mid=(a+b)>>1;
  if(c<=mid)change(x<<1,a,mid,c,p);
  else change(x<<1|1,mid+1,b,c,p);
}
inline void upd(){
  int a=0,b=100010,mid,x=1;
  while(a<b){
    mid=(a+b)>>1;
    if(v[x<<1|1])a=mid+1,x=x<<1|1;else b=mid,x<<=1;
  }
  ans=min(ans,1LL*a*v[x]);
}
int main(){
  scanf("%d",&n);
  for(i=1;i<=n;i++)scanf("%d",&a[i]);
  for(i=1;i<=n;i++)change(1,0,100010,a[i],1);
  upd();
  for(i=1;i<n;i++){
    if(a[i]){
      change(1,0,100010,a[i],-1);
      change(1,0,100010,a[i]-1,1);
      change(1,0,100010,a[i+1],-1);
      change(1,0,100010,a[i+1]+1,1);
      upd();
      change(1,0,100010,a[i],1);
      change(1,0,100010,a[i]-1,-1);
      change(1,0,100010,a[i+1],1);
      change(1,0,100010,a[i+1]+1,-1);
    }
  }
  for(i=2;i<=n;i++){
    if(a[i]){
      change(1,0,100010,a[i],-1);
      change(1,0,100010,a[i]-1,1);
      change(1,0,100010,a[i-1],-1);
      change(1,0,100010,a[i-1]+1,1);
      upd();
      change(1,0,100010,a[i],1);
      change(1,0,100010,a[i]-1,-1);
      change(1,0,100010,a[i-1],1);
      change(1,0,100010,a[i-1]+1,-1);
    }
  }
  printf("%lld",ans);
}

  

时间: 2024-10-12 13:08:19

XV Open Cup named after E.V. Pankratiev. GP of Tatarstan的相关文章

XV Open Cup named after E.V. Pankratiev. GP of Siberia-Swimming

给出两个点,找到过这两个点的等角螺线,并求出中间的螺线长 $c = \frac{b}{a}$ $p = a \times c^{\frac{\theta}{angle}}$ 对弧线积分 #include <bits/stdc++.h> using namespace std; long double eps = 1e-8; struct Point { long double x, y; Point(long double _x = 0, long double _y = 0) { x = _

XV Open Cup named after E.V. Pankratiev Stage 6, Grand Prix of Japan Problem J. Hyperrectangle

题目大意: 给出一个$d$维矩形,第i维的范围是$[0, l_i]$. 求满足$x_1 + x_2 + ...x_d \leq s$ 的点构成的单纯形体积. $d, l_i \leq 300$ 题解: watashi学长的blog传送门. 给出了求$a_1x_1 + a_2x_2 + ...a_dx_d \leq b $的通用做法.答案就是一个神奇的式子$\frac{1}{n!} * \sum_{I \subseteq S}{(-1)^{|I|}}*max\{0, b - \sum_{i \in

XVI Open Cup named after E.V. Pankratiev. GP of Eurasia

A. Nanoassembly 首先用叉积判断是否在指定向量右侧,然后解出法线与给定直线的交点,再关于交点对称即可. #include<bits/stdc++.h> using namespace std; const int Maxn=300020; typedef long long LL; typedef pair<int,int>pi; struct P{ double x,y; P(){x=y=0;} P(double _x,double _y){x=_x,y=_y;}

XVI Open Cup named after E.V. Pankratiev. GP of SPB

A. Bubbles 枚举两个点,求出垂直平分线与$x$轴的交点,答案=交点数+1. 时间复杂度$O(n^2\log n)$. #include<cstdio> #include<algorithm> #include<cmath> using namespace std; const double eps=1e-9; int sgn(double x){ if(x<-eps)return -1; if(x>eps)return 1; return 0; }

XVI Open Cup named after E.V. Pankratiev. GP of Ekaterinburg.

贼惨 130/186 B Black Widow 简单题 #include <bits/stdc++.h> const long long mod = 1e9+7; const double ex = 1e-10; #define inf 0x3f3f3f3f using namespace std; map <int,int> M; int a[1010]; int b[100010]; int main() { int N; scanf("%d",&

XVII Open Cup named after E.V. Pankratiev. GP of SPb

A. Array Factory 将下标按前缀和排序,然后双指针,维护最大的右边界即可. #include<cstdio> #include<algorithm> using namespace std; typedef long long ll; const int N=200010; int n,i,j,anslen,ansl,ansr,mr,q[N]; ll a[N],lim; inline bool cmp(int x,int y){return a[x]<a[y];

XVII Open Cup named after E.V. Pankratiev. GP of Two Capitals

A. Artifact Guarding 选出的守卫需要满足$\max(a+b)\leq \sum a$,从小到大枚举每个值作为$\max(a+b)$,在权值线段树上找到最大的若干个$a$即可. 时间复杂度$O(n\log n)$. #include<cstdio> #include<algorithm> #include<set> #include<map> using namespace std; typedef long long ll; const

XIII Open Cup named after E.V. Pankratiev. GP of Asia and South Caucasus

A. RPG 首先计算出每个技能对于每个属性值的可行区间,若区间为空则不合法. 枚举两个技能,以及每个属性值,根据区间的关系可以得到哪个必须要在另一个之前学,连边看看是否有环即可. 时间复杂度$O(n^2m)$. #include<stdio.h> #include<algorithm> #include<math.h> #include<string.h> #include<string> #include<vector> #inc

XIII Open Cup named after E.V. Pankratiev. GP of Azov Sea

A. Freestyle 如果逆序对为$0$,那么先手必败. 因为每次只能翻转长度为$4k+2$和$4k+3$的区间,所以每次操作之后逆序对的奇偶性一定会发生改变. 因此如果逆序对个数为偶数,则先手必败. #include<stdio.h> #include<algorithm> #include<math.h> #include<string.h> #include<string> #include<vector> #include