zoukankan      html  css  js  c++  java
  • 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(nlog^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
    ",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
    ",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(nlog 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
    ",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
    ",res[i]);
    			ans=1LL*ans*powmod(pri[i+1],res[i])%mod;
    		}
    		printf("%d
    ",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
    ",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
    ",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
    ",tmp);
    			if((long double)ned*(x-i+1)+10<(long double)tmp*(i))return 0;
    			tmp=tmp*i/(x-i+1);
    		}
    	}
    	//printf("tmp=%lld
    ",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
    ",l,r);
    	}
    	return l;
    }
    int main(){
    	//n=10000000000000LL;
    	//m=2;
    	//printf("%lld",cal(4472136LL));
    	//solve(7937589951629LL);
    	//printf("%d
    ",check(n/2,7937589951629LL));
    	//m=10;
    	///printf("%d
    ",check(10,1));
    	while(scanf("%lld%lld",&n,&m)!=EOF){
    		//solve(n);
    		//printf("%d
    ",check(7,n));
    		
    		int tot=m;
    		LL pre=1e9;
    		for(int i=1;i<=tot;i++){
    			LL tmp=solve(n);
    			//printf("tmp=%lld
    ",tmp);
    			tmp=min(tmp,pre-1);
    			pre=tmp;
    			n-=cal(tmp);
    			printf("%lld%c",tmp,i==tot?'
    ':' ');
    			//printf("tmp=%lld n=%lld
    ",tmp,n);
    			m--;
    		}
    		//printf("n=%lld
    ",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);
    }
    

      

  • 相关阅读:
    linux常用命令
    10.8统计英文词频
    9月10号作业
    华氏温度与摄氏温度转换
    小故事
    Java的工厂模式(三)
    Javascript实现图片翻转
    Java的工厂模式(二)
    Java的工厂模式(一)
    Java新建线程的两种方式
  • 原文地址:https://www.cnblogs.com/clrs97/p/6147743.html
Copyright © 2011-2022 走看看