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

A. Area of Effect

首先最优解中必有一个点在圆的边界上。

若半径就是$R$,则枚举一个点,然后把剩下的事件极角扫描即可,时间复杂度$O(m(n+m)\log(n+m))$。

否则圆必然撞到了两个圆,枚举一个点以及两个圆,二分出最大的半径,然后统计内部点数即可,时间复杂度$O(n^2m(n+m))$。

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<ld,int>P;
const int N=2100;
const ld eps=1e-9,eps2=1e-4,pi=acos(-1.0);
int n,m,i,j,k,ans=1;ll R,d[N][N];P q[N*2];
struct C{ll x,y,r;}a[N];
struct Circle{
  ld x,y,r;
  Circle(){}
  Circle(ld _x,ld _y,ld _r){x=_x,y=_y,r=_r;}
};
inline int sgn(ld x){
  if(x>eps)return 1;
  if(x<-eps)return -1;
  return 0;
}
inline int sgn2(ld x){
  if(x>eps2)return 1;
  if(x<-eps2)return -1;
  return 0;
}
inline ll sqr(ll x){return x*x;}
inline ld sqr(ld x){return x*x;}
inline void fix(ld&x){
  while(sgn(x)<0)x+=pi*2;
  while(sgn(x-pi*2)>=0)x-=pi*2;
  x=max(x,(ld)0.0);
}
inline void solve1(int x){
  int i,ret=1,cnt=0;
  for(i=1;i<=n+m;i++)if(i!=x){
    if(d[x][i]>sqr(R*2+a[i].r))continue;
    if(d[x][i]==sqr(R*2+a[i].r)&&i<=n)continue;
    ld A=R,B=R+a[i].r,C=sqrt(d[x][i]);
    if(i<=n)B-=1e-6;
    ld o=acos((A*A+d[x][i]-B*B)/(2.0*A*C));
    ld w=atan2(a[i].y-a[x].y,a[i].x-a[x].x);
    ld l=w-o,r=w+o;
    fix(l),fix(r);
    if(!sgn(l-r))r=l+eps;
    int v=i<=n?-N:1;
    if(l>r)ret+=v;
    q[++cnt]=P(l,v),q[++cnt]=P(r,-v);
  }
  ans=max(ans,ret);
  sort(q+1,q+cnt+1);
  for(i=1;i<=cnt;i++)ans=max(ans,ret+=q[i].second);
}
inline void circle_intersection(const Circle&a,const Circle&b,ld&X,ld&Y,int t){
  ld d2=sqr(a.x-b.x)+sqr(a.y-b.y),d=sqrt(d2);
  ld l=(d2+sqr(a.r)-sqr(b.r))/(2.0*d),h=sqrt(max(sqr(a.r)-sqr(l),(ld)0.0));
  ld vlx=(b.x-a.x)/d*l,vly=(b.y-a.y)/d*l;
  ld vhx=-(b.y-a.y)/d*h,vhy=(b.x-a.x)/d*h;
  if(t==1)vhx*=-1,vhy*=-1;
  X=a.x+vlx+vhx;
  Y=a.y+vly+vhy;
}
inline void work(ld x,ld y,ld r){
  for(int i=1;i<=n;i++)if(sgn2(sqr(x-a[i].x)+sqr(y-a[i].y)-sqr(r+a[i].r))<0)return;
  int ret=0;
  r=sqr(r);
  for(int i=n+1;i<=n+m;i++)if(sgn2(sqr(x-a[i].x)+sqr(y-a[i].y)-r)<=0)ret++;
  ans=max(ans,ret);
}
inline void solve3(int x,int y,int z){
  if(d[x][y]>=sqr(R*2+a[x].r+a[y].r))return;
  for(int _=0;_<2;_++){
    ld l=(sqrt(d[x][z])-a[x].r)/2.0,r=R,X,Y;
    for(int i=0;i<100;i++){
      ld mid=(l+r)/2.0;
      circle_intersection(Circle(a[x].x,a[x].y,a[x].r+mid),Circle(a[z].x,a[z].y,mid),X,Y,_);
      if(sgn2(sqr(X-a[y].x)+sqr(Y-a[y].y)-sqr(a[y].r+mid))>=0)l=mid;else r=mid;
    }
    circle_intersection(Circle(a[x].x,a[x].y,a[x].r+l),Circle(a[z].x,a[z].y,l),X,Y,_);
    work(X,Y,l);
  }
}
int main(){
  scanf("%d%d%lld",&n,&m,&R);
  for(i=1;i<=n;i++)scanf("%lld%lld%lld",&a[i].x,&a[i].y,&a[i].r);
  for(i=1;i<=m;i++)scanf("%lld%lld",&a[i+n].x,&a[i+n].y);
  for(i=1;i<=n+m;i++)for(j=1;j<=n+m;j++)d[i][j]=sqr(a[i].x-a[j].x)+sqr(a[i].y-a[j].y);
  for(i=1;i<=m;i++)solve1(i+n);
  for(i=1;i<=n;i++)for(j=1;j<i;j++)for(k=1;k<=m;k++)solve3(i,j,k+n);
  printf("%d",ans);
}

  

B. Canyon Mapping

二分答案,求出多边形的包围盒,那么某个正方形的某个顶点必然与包围盒的某个顶点重合,爆搜即可。

时间复杂度$O(4^3n\log w)$。

 

C. Magic Checkerboard

枚举奇偶性然后贪心构造即可。

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() {  }
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 2020, M = 0, Z = 1e9 + 7; LL inf = 1e18;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
int n,m;
int a[N][N];
int b[N][N];
void tryit(int y, int x, int oe)
{
    int val = 2 - oe;
    if(x > 1)gmax(val, b[y][x - 1] + 1);
    if(y > 1)gmax(val, b[y - 1][x] + 1);
    if(val % 2 != oe)++val;
    b[y][x] = val;
}
void hahatry(int y, int x)
{
    int val = 1;
    if(x > 1)gmax(val, b[y][x - 1] + 1);
    if(y > 1)gmax(val, b[y - 1][x] + 1);
    b[y][x] = val;
}
LL checkok()
{
    LL sum = 0;
    for(int i = 1; i <= n; ++i)
    {
        for(int j = 1; j <= m; ++j)
        {
            if(i > 1 && b[i][j] <= b[i - 1][j])return inf;
            if(j > 1 && b[i][j] <= b[i][j - 1])return inf;
            if(i > 1)
            {
                if(j > 1)
                {
                    if((b[i][j] ^ b[i - 1][j - 1]) % 2 == 0)return inf;
                }
                if(j < m)
                {
                    if((b[i][j] ^ b[i - 1][j + 1]) % 2 == 0)return inf;
                }
            }
            sum += b[i][j];
        }
    }
    return sum;
}
LL solve()
{
    for(int i = 1; i <= n; ++i)
    {
        for(int j = 1; j <= m; ++j)
        {
            if(i > 1)
            {
                if(j > 1 && a[i][j] * a[i - 1][j - 1])
                {
                    if((a[i][j] ^ a[i - 1][j - 1]) % 2 == 0)return -1;
                }
                if(j < m && a[i][j] * a[i - 1][j + 1])
                {
                    if((a[i][j] ^ a[i - 1][j + 1]) % 2 == 0)return -1;
                }
            }
        }
    }
    LL ans = inf;
    for(int x = 0; x < 2; ++x)
    //int x = 1;
    {
        for(int y = 0; y < 2; ++y)
        //int y = 0;
        {
            memcpy(b, a, sizeof(a));
            for(int i = 1; i <= n; ++i)
            {
                for(int j = 1; j <= m; ++j)if(b[i][j] == 0)
                {
                    if((i + j) % 2 == 0)
                    {
                        if((i - 1) % 2 == 0)
                        {
                            if(n == 1 || m == 1)hahatry(i,j);
                            else tryit(i, j, x);
                        }
                        else
                        {
                            if(n == 1 || m == 1)hahatry(i,j);
                            else tryit(i, j, 1 ^ x);
                        }
                    }
                    else
                    {
                        if((i - 1) % 2 == 0)
                        {
                            if(n == 1 || m == 1)hahatry(i,j);
                            else tryit(i, j, y);
                        }
                        else
                        {
                            if(n == 1 || m == 1)hahatry(i,j);
                            else tryit(i, j, 1 ^ y);
                        }
                    }
                }
            }
            if(0)for(int i = 1; i <= n; ++i)
            {
                for(int j = 1; j <= m; ++j)printf("%d ", b[i][j]);
                puts("");
            }
            gmin(ans, checkok());
        }
    }
    if(ans == inf)ans = -1;
    return ans;
}
int main()
{
	while(~scanf("%d%d",&n,&m))
	{
        for(int i = 1; i <= n; ++i)
        {
            for(int j = 1; j <= m; ++j)
            {
                scanf("%d", &a[i][j]);
            }
        }
        printf("%lld\n", solve());
	}
	return 0;
}

/*
【trick&&吐槽】
4 4
1 2 3 0
0 0 5 6
0 0 7 8
7 0 0 10

4 4
1 2 3 0
0 0 5 6
0 4 7 8
7 0 0 10

2 3
0 0 0
0 0 0

【题意】


【分析】


【时间复杂度&&优化】


*/

  

D. Extensive OR

从高到低考虑每一位,一旦有个数字脱离了限制,也就是说这个数字这一位是$1$,但是强制填了$0$。那么除了这一位之外,其它位可以乱填,它自己方案唯一。
枚举脱离的那一位,设$f[i][j][l]$表示前$i$个数字,当前位$xor$为$j$,是否有数字脱离限制的方案数。如此求出$g[i]$表示$i$个数(允许重复)的答案。

考虑容斥,枚举$n$的所有等价类方案,贡献为:

$(-1)^{n-等价类个数}\ \ \ \ \ \ \ \times(每个等价类大小-1)!之积\times 方案数$

$方案数=g[奇数大小的等价类个数]\times g[2]^{偶数大小的等价类个数}$。

最后答案再除以$n!$即可。

时间复杂度$O(nk|S|+Bell(n))$。

#include<cstdio>
#include<cstring>
const int N=10,P=1000000007,inv=(P+1)/2;
int n,m,K,i,j,k,x,y,o,f[N][2][2],g[N],w[N],ans;
char a[5000050],flag[N];
int pow(int a,int b){
	int t=1;
	for(;b;b>>=1,a=1LL*a*a%P)if(b&1)t=1LL*t*a%P;
	return t;
}
inline void up(int&a,int b){a=a+b<P?a+b:a+b-P;}
void dfs(int x,int y){
	if(x==n){
		int i,j,k=(n-y)&1?-1:1,t=0;
		for(i=1;i<=y;i++){
			for(j=2;j<w[i];j++)k*=j;
			if(w[i]&1)t++;
		}
		if(k<0)k+=P;
		ans=(1LL*k*g[t]%P*pow(g[2],y-t)+ans)%P;
		return;
	}
	for(int i=1;i<=y+1;i++){
		w[i]++;
		dfs(x+1,i>y?i:y);
		w[i]--;
	}
}
int main(){
	scanf("%d%d%s",&n,&K,a);
	m=strlen(a);
	for(i=0;i<m;i++)for(j=1,k=i+m;j<K;j++,k+=m)a[k]=a[i];
	m*=K;
	for(i=0;i<m;i++)a[i]-='0';
	for(i=m-1;~i;i--){
		a[i]^=1;
		if(!a[i])break;
	}
	f[0][0][0]=1;
	y=pow(2,m);
	for(i=0;i<m;i++)x=(x*2+a[i])%P;
	up(x,1);
	for(i=m-1;~i;i--){
		y=1LL*y*inv%P;
		o=a[m-i-1];
		if(o)up(x,P-y);
		if(o){
			for(j=1;j<=n;j++){
				f[j][0][0]=f[j][0][1]=f[j][1][0]=f[j][1][1]=0;
				for(k=0;k<2;k++){
					if(f[j-1][k][0]){
						f[j][k^1][0]=(1LL*f[j-1][k][0]*x+f[j][k^1][0])%P;
						up(f[j][k][1],f[j-1][k][0]);
					}
					if(f[j-1][k][1]){
						f[j][k][1]=(1LL*f[j-1][k][1]*y+f[j][k][1])%P;
						f[j][k^1][1]=(1LL*f[j-1][k][1]*x+f[j][k^1][1])%P;
					}
				}
			}
		}else{
			for(j=1;j<=n;j++){
				f[j][0][0]=f[j][0][1]=f[j][1][0]=f[j][1][1]=0;
				for(k=0;k<2;k++){
					if(f[j-1][k][0]){
						f[j][k][0]=(1LL*f[j-1][k][0]*x+f[j][k][0])%P;
					}
					if(f[j-1][k][1]){
						f[j][k][1]=(1LL*f[j-1][k][1]*x+f[j][k][1])%P;
					}
				}
			}
		}
		for(j=1;j<=n;j++)if(!flag[j]){
			up(g[j],f[j][0][1]);
			if(o&(j&1))flag[j]=1;
		}
	}
	for(i=1;i<=n;i++)if(!flag[i])up(g[i],1);
	g[0]=g[1]=1;
	dfs(0,0);
	for(i=2;i<=n;i++)ans=1LL*ans*pow(i,P-2)%P;
	printf("%d",ans);
}

  

E. Primal Partitions

设$f[i][j]$表示把$[1,j]$分成$i$段的最大得分,注意到区间$\gcd$只有本质不同的$O(n\log v)$段,用ST表优化转移即可。

时间复杂度$O(nk\log n)$。

#include<cstdio>
const int N=20010,M=1000010;
int n,m,i,j,tot,p[M],vis[M],w[M],l[N],v[N];
int a[N],Log[N],dp[N],f[15][N];
struct E{
	int x,y,r,w;
	E(){}
	E(int _x,int _y,int _r,int _w){x=_x,y=_y,r=_r,w=_w;}
}e[M];
inline int max(int a,int b){return a>b?a:b;}
inline int min(int a,int b){return a<b?a:b;}
inline void up(int&a,int b){a<b?(a=b):0;}
int gcd(int a,int b){return b?gcd(b,a%b):a;}
inline int ask(int l,int r){
	int k=Log[r-l+1];
	return max(f[k][l],f[k][r-(1<<k)+1]);
}
int main(){
	scanf("%d%d",&n,&m);
	for(i=2;i<=1000000;i++){
		if(!vis[i])vis[i]=i,p[tot++]=i;
		for(j=0;j<tot&&i*p[j]<=1000000;j++){
			vis[i*p[j]]=p[j];
			if(i%p[j]==0)break;
		}
	}
	for(i=2;i<=1000000;i++){
		j=i;
		while(j>1){
			w[i]=max(w[i],vis[j]);
			j/=vis[j];
		}
	}
	for(i=1;i<=n;i++)scanf("%d",&a[i]);
	tot=0;
	for(i=1;i<=n;i++)for(v[i]=a[i],j=l[i]=i;j;j=l[j]-1){
		v[j]=gcd(v[j],a[i]);
		while(l[j]>1&&gcd(a[i],v[l[j]-1])==gcd(a[i],v[j]))l[j]=l[l[j]-1];
		e[++tot]=E(l[j],j,i,w[v[j]]);
	}
	dp[1]=a[1];
	for(i=2;i<=n;i++)dp[i]=gcd(dp[i-1],a[i]);
	for(i=1;i<=n;i++)dp[i]=w[dp[i]];
	for(i=2;i<=n+1;i++)Log[i]=Log[i>>1]+1;
	while(m>1){
		m--;
		for(i=0;i<=n;i++)f[0][i]=dp[i],dp[i]=0;
		for(j=1;j<15;j++)for(i=0;i+(1<<j)-1<=n;i++)f[j][i]=max(f[j-1][i],f[j-1][i+(1<<(j-1))]);
		for(i=1;i<=tot;i++)up(dp[e[i].r],min(ask(e[i].x-1,e[i].y-1),e[i].w));
	}
	printf("%d",dp[n]);
}

  

F. Sand Art

二分差值,显然最高的是不变的,对于剩下的用网络流判定是否有解即可。

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 420, M = 1e6 + 10, Z = 1e9 + 7;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
const double inf = 1e9;

int ST, ED;
int first[N], id;
int w[M], nxt[M];
double cap[M];

void ins(int x, int y, double cap_)
{
    w[++ id] = y;
    cap[id] = cap_;
    nxt[id] = first[x];
    first[x] = id;
    w[++ id] = x;
    cap[id] = 0;
    nxt[id] = first[y];
    first[y] = id;
}
int d[N];
const double eps = 1e-6;
int sgn(double x)
{
    if(fabs(x) < eps) return 0;
    return x > 0 ? 1 : -1;
}

bool bfs()
{
    MS(d, -1);
    queue<int> q; q.push(ST); d[ST] = 0;
    while(! q.empty()){
        int x = q.front(); q.pop();
        for(int z = first[x]; z; z = nxt[z]) if(sgn(cap[z])){
            int y = w[z];
            if(d[y] == -1){
                d[y] = d[x] + 1;
                q.push(y);
                if(y == ED) return 1;
            }
        }
    }
    return 0;
}

double dfs(int x, double all)
{
    if(x == ED) return all;
    double use = 0;
    for(int z = first[x]; z; z = nxt[z]) if(sgn(cap[z])){
        int y = w[z];
        if(d[y] == d[x] + 1){
            double tmp = dfs(y, min(cap[z], all - use));
            cap[z] -= tmp;
            cap[z ^ 1] += tmp;
            use += tmp;
            if(sgn(use - all) == 0) break;
        }
    }
    if(sgn(use) == 0) d[x] = -1;
    return use;
}


double dinic()
{
    double ret = 0;
    while(bfs()) ret += dfs(ST, inf);
    return ret;
}
int n, m;
double v[N], h[N], W, H, x[N];
double minv[N][N], maxv[N][N];
double minh, maxh;

bool build(double mid)
{
    double top = maxh - mid;
    MS(first, 0); id = 1;
    double allv = 0;
    for(int i = 1; i <= n; i ++){
        if(sgn(top - h[i]) > 0) allv += (top - h[i]) * x[i];
    }
    for(int j = 1; j <= m; j ++){
        for(int i = 1; i <= n; i ++){
            if(sgn(top - h[i]) > 0) {
                double cap_ = min((top - h[i]) * x[i], maxv[i][j] - minv[i][j]);
                ins(j, i + m, cap_);
            }
        }
    }
    ST = 0, ED = n + m + 1;
    for(int i = 1; i <= n; i ++){
        if(sgn(top - h[i]) > 0) ins(i + m, ED, (top - h[i]) * x[i]);
    }
    for(int i = 1; i <= m; i ++){
        ins(ST, i, v[i]);
    }
    if(sgn(dinic() - allv) != 0) return 1;
    return 0;
}

int main()
{
	scanf("%d%d%lf%lf", &n, &m, &W, &H);
	for(int i = 1; i <= m; i ++){
        scanf("%lf", &v[i]);
	}
	for(int i = 1; i < n; i ++){
        scanf("%lf", &x[i]);
	}
	x[n] = W;
	for(int i = n; i >= 1; i --){
        x[i] = x[i] - x[i - 1];
        //x[i] *= H;
	}  // 每个容器的宽度

	for(int i = 1; i <= n; i ++){
        for(int j = 1; j <= m; j ++){
            scanf("%lf", &minv[i][j]);
        }
	}
	for(int i = 1; i <= n; i ++){
        for(int j = 1; j <= m; j ++){
            scanf("%lf", &maxv[i][j]);
        }
	}
	maxh = 0, minh = 1e9;
	for(int i = 1; i <= n; i ++){
        for(int j = 1; j <= m; j ++){
            h[i] += minv[i][j] / x[i];
            v[j] -= minv[i][j];
        }
        gmax(maxh, h[i]);
        gmin(minh, h[i]);
	}
	double r = maxh - minh, l = 0;
	for(int tim = 1; tim <= 200; tim ++){
        double mid = (l + r) / 2;
        if(build(mid)) l = mid;
        else r = mid;
	}
	printf("%.6f\n", l);
	return 0;
}
/*
【trick&&吐槽】

2 2 5 5
2.0 2.0
4.0
1.0 0.0
0.0 1.0
1.0 0.0
1.0 2.0

2 2 5 5
2.0 2.0
4.0
1.0 0.0
0.0 1.0
1.5 0.0
0.0 2.0

2 5 11 10
3.0 4.0 4.0 9.0 2.0
4.0
2.0 2.0 1.0 0.5 0.25
0.0 2.0 0.0 4.0 1.0
2.0 2.0 3.0 4.0 0.75
0.0 2.1 0.0 5.1 1.1




【题意】


【分析】


【时间复杂度&&优化】


*/

  

G. String Stretching

枚举长度$len$,那么$len$必须要是$n$的约数,然后枚举每个长度为$len$的子串$S$,检查是否可行。

对于检查,设$f[i][j]$表示区间$[i,j]$能否通过$S$产生,要么在末尾产生某个长度为$len$倍数的区间,要么接着匹配一位,时间复杂度$O(\frac{n^3}{len})$。

总时间复杂度$O(n^3d(n)\log n)$。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=210;
char a[N],b[N],c[N],fin[N];
int n,i;
int cnt;
bool f[N][N];
string best;
inline bool check(int len,string cur){
	int i,j,k;
	//cout<<len<<" "<<cur<<endl;
	for(i=1;i<=len;i++)b[i]=cur[i-1];
	int tot=0;
	for(i=1;i*len<=n;i++)for(j=1;j<=len;j++)c[++tot]=b[j];
	sort(c+1,c+n+1);
	for(i=1;i<=n;i++)if(c[i]!=fin[i])return 0;
	for(i=0;i<=n+1;i++)for(j=0;j<=n+1;j++)f[i][j]=0;
	for(i=n;i;i--){
		f[i][i-1]=1;
		for(j=i;j<=n;j++){
			for(k=j-len;k>=i-1;k-=len){
				if(f[i][k]&&f[k+1][j]){f[i][j]=1;break;}
			}
			int o=j-i+1;
			o%=len;
			if(!o)o+=len;
			if(f[i][j-1]&&a[j]==b[o])f[i][j]=1;
		}
	}
	return f[1][n];
}
void solve(int len){
	if(n%len)return;
	for(int i=1;i+len-1<=n;i++){
		string now="";
		for(int j=0;j<len;j++)now.push_back(a[i+j]);
		if(cnt&&best<=now)continue;
		if(check(len,now)){
			cnt++;
			best=now;
		}
	}
	if(cnt){
		cout<<best<<endl;
		exit(0);
	}
}
int main(){
	scanf("%s",a+1);
	n=strlen(a+1);
	for(i=1;i<=n;i++)fin[i]=a[i];
	sort(fin+1,fin+n+1);
	for(i=1;i<n;i++)solve(i);
	puts(a+1);
}
/*
hhehellolloelhellolo
*/

  

H. Vending Machine

将差值看成边权,并添加$0$边来消除负数,首先可以贪心将每个点都买到剩一个。

那么若是树或者自环,则答案为每个点的入边中权值的最大值。

对于环来说,必须要删掉环上一条边,枚举每条边删除即可。

时间复杂度$O(n\log n)$。

#include<cstdio>
#include<set>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;//w[son],son
const int N=100010;
int n,i,j,k,f[N],p[N],m[N],s[N],w[N];
ll ans;
int t,q[N];
int fa[N],vf[N],vis[N];
set<P>T[N];
int F(int x){return fa[x]==x?x:fa[x]=F(fa[x]);}
inline void merge(int x,int y){
	if(F(x)!=F(y))fa[fa[x]]=fa[y];
}
inline ll cal(int x){
	int y=f[x];
	ll pre=T[y].rbegin()->first;
	T[y].erase(P(w[x],x));
	ll now=T[y].rbegin()->first;
	T[y].insert(P(w[x],x));
	return now-pre;
}
int main(){
	scanf("%d",&n);
	for(i=1;i<=n;i++)scanf("%d%d%d%d",&f[i],&p[i],&m[i],&s[i]);
	for(i=1;i<=n;i++)T[i].insert(P(0,0));
	for(i=1;i<=n;i++){
		w[i]=m[f[i]]-p[i];
		T[f[i]].insert(P(w[i],i));
	}
	for(i=1;i<=n;i++)ans+=1LL*(T[i].rbegin()->first)*s[i];
	for(i=1;i<=n;i++)fa[i]=i;
	for(i=1;i<=n;i++)merge(i,f[i]);
	for(i=1;i<=n;i++)if(!vf[F(i)]){
		vf[fa[i]]=1;
		for(j=i;!vis[j];j=f[j])vis[j]=1;
		q[t=1]=j;
		for(k=f[j];k!=j;k=f[k])q[++t]=k;
		if(t==1)continue;
		ll tmp=-(1LL<<60);
		for(j=1;j<=t;j++){
			tmp=max(tmp,cal(q[j]));
		}
		ans+=tmp;
	}
	printf("%lld",ans);
}
/*
5
5 9 2 2
1 1 7 4
2 3 6 3
2 2 9 6
1 4 5 1
*/

  

I. Rainbow Zamboni

首先通过公式直接求出终点,然后倒着模拟,最多模拟$O(R+C)$轮后每个点都会被经过至少一次,无需接着模拟。

时间复杂度$O((R+C)^2)$。

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
ll x, y;
ll n;
int R,C;
int ret;
const int N=2222;
char f[N][N],vis[N][N];

void solve(int d, ll i)
{
	if(d==0){
		x+=i;
	}
	if(d==1){
		y-=i;
	}
	if(d==2){			
		x-=i;
	}
	if(d==3){
		y+=i;
	}
		
	if(d==0){
		y++;
	}
	if(d==1){
		x++;
	}
	if(d==2){
		y--;
	}
	if(d==3){
		x--;
	}
		
}

ll mo(ll a,ll b){return (a%b+b)%b;}

inline void col(int x,int y,int c){
	if(!vis[x][y]){
		vis[x][y]=1;
		f[x][y]=c;
		ret--;
	}
}
inline void moveup(int x,int l,int r,int c){
	for(int i=l;i<=r;i++)col(x,i,c);
}
inline void moveright(int y,int l,int r,int c){
	for(int i=l;i<=r;i++)col(i,y,c);
}

inline void walk(ll x1,ll y1,ll x2,ll y2,int c){
	if(x1==x2){
		if(y1>y2)swap(y1,y2);
		ll k=y2-y1+1;
		y1=mo(y1,C);
		if(k>=C)moveup(mo(x1,R),0,C-1,c);
		else{
			if(y1+k-1<C)moveup(mo(x1,R),y1,y1+k-1,c);
			else{
				moveup(mo(x1,R),y1,C-1,c);
				moveup(mo(x1,R),0,mo(y2,C),c);
			}
		}
	}else{
		if(x1>x2)swap(x1,x2);
		ll k=x2-x1+1;
		x1=mo(x1,R);
		if(k>=R)moveright(mo(y1,C),0,R-1,c);
		else{
			if(x1+k-1<R)moveright(mo(y1,C),x1,x1+k-1,c);
			else{
				moveright(mo(y1,C),x1,R-1,c);
				moveright(mo(y1,C),0,mo(x2,R),c);
			}
		}
	}
}

void solve2(ll n, int d,int c)
{
	ll xx = x, yy = y;
	if(d == 0){		// rgt
		x += n;
	}
	else if(d == 1){	// down
		y -= n;
	}
	else if(d == 2){	// lft
		x -= n;
	}	
	else if(d == 3){	// up
		y += n;
	}
	walk(xx,yy,x,y,c);
	if(d == 0){		// rgt
		y ++;
	}
	else if(d == 1){	// down
		x ++;
	}
	else if(d == 2){	// lft
		y --;
	}	
	else if(d == 3){	// up
		x --;
	}
}
int main()
{
	scanf("%d%d",&R,&C);
	scanf("%lld%lld",&x,&y);
	
	
	x=R-x+1;
	swap(x,y);
	swap(R,C);
	
	scanf("%lld", &n);
	
	x--,y--;
	x%=R;
	y%=C;
	
	
	ll A = n / 4, B = n % 4;
	x += -2 * A + 1, y += -2 * A;
	x%=R;
	y%=C;
	for(int i = 0; i < B; i ++){
		solve((i+3)%4, A * 4 + i);
		x%=R;
		y%=C;
	}
	for(int i=0;i<R;i++)for(int j=0;j<C;j++){
		f[i][j]='.';
		ret++;
	}
	if(n%4==0){
		col(mo(x-1,R),mo(y,C),'@');
	}
	if(n%4==1){
		col(mo(x,R),mo(y+1,C),'@');
	}
	if(n%4==2){
		col(mo(x+1,R),mo(y,C),'@');
	}
	if(n%4==3){
		col(mo(x,R),mo(y-1,C),'@');
	}
	for(ll i=n;i;i--){
		solve2(i-1, i % 4,(i-1+26)%26+'A');
		x%=R;
		y%=C;
		if(!ret)break;
	}
	for(int j=C-1;~j;j--){
		for(int i=0;i<R;i++)putchar(f[i][j]);
		puts("");
	}
}

  

J. Zig Zag Nametag

贪心构造即可。

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() {  }
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 1e6 + 30, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
int n, K;
int f[N][26];
void print(int len, int first)
{
    printf("%c", 'a' + first);
    for(int nxt = 0; nxt < 26; ++nxt)
    {
        int add = abs(first - nxt);
        if(len >= add && f[len - add][nxt] + 1 == f[len][first])
        {
            print(len - add, nxt);
            break;
        }
    }
}
char s[N];
int main()
{
	while(~scanf("%d",&K))
    {
        int n = K / 25 + (K % 25 > 0) + 1;
        for(int i = 1; i <= n; ++i)
        {
            s[i] = i % 2 == 1 ? 'a' : 'z';
        }
        s[n + 1] = 0;
        int dif = (n - 1) * 25 - K;
        if(n == 2)
        {
            s[2] -= dif;
        }
        else
        {
            int diff = dif / 2;
            s[2] -= diff;
            if(s[n] == 'a')s[n] += dif % 2;
            else s[n] -= dif % 2;
        }
        puts(s + 1);
    }
	return 0;
	for(K = 1; K <= 200; ++K)
	{
        MS(f, 63);
	    for(int j = 0; j < 26; ++j)
        {
            f[0][j] = 1;
        }
        for(int i = 0; i <= K; ++i)
        {
            for(int j = 0; j < 26; ++j)if(f[i][j] != inf)
            {
                for(int k = 0; k < 26; ++k)
                {
                    int add = abs(j - k);
                    gmin(f[i + add][k], f[i][j] + 1);
                }
            }
        }
        int len = -1, pos = 0;
        for(int i = 0; i < 26; ++i)
        {
            if(f[K][i] < len)
            {
                len = f[K][i];
                pos = i;
            }
        }
        print(K, pos);
        puts("");
	}
	return 0;
}

/*
【trick&&吐槽】


【题意】


【分析】


【时间复杂度&&优化】


*/

  

posted @ 2017-12-12 01:15  Claris  阅读(761)  评论(0编辑  收藏  举报