A.Peter and Snow Blower(计算几何)
给定一个点和一个多边形,求出这个多边形绕这个点旋转一圈后形成的面积。
保证这个点不在多边形内。
画个图能明白 这个图形是一个圆环,那么就是这个点距离多边形边缘最远的距离形成的圆面积减去这个点距离多边形边缘最近的距离形成的圆面积。
我们可以得出距离最远的点一定是多边形的顶点。
而距离最近的点不一定是多边形的顶点,但是在多边形的边上。
我们用勾股定理判断点与每条边形成的三角形的两边角。
如果有一个边角是钝角,则表示距离最近的点是顶点。
如果都是锐角,则表示距离最近的点在底边上。
我们用海伦公式求出三角形的面积,再除以底边*2,那么就得出了这个三角形的高。
此题得解。
# include <stdio.h> # include <string.h> # include <stdlib.h> # include <iostream> # include <vector> # include <queue> # include <stack> # include <map> # include <math.h> # include <algorithm> using namespace std; # define lowbit(x) ((x)&(-x)) # define pi acos(-1.0) # define MAXN 100005 # define eps 1e-5 # define MAXM 1000005 # define MOD 1000000007 # define INF 1000000000 # define mem(a,b) memset(a,b,sizeof(a)) # define FOR(i,a,n) for(int i=a; i<=n; ++i) # define FO(i,a,n) for(int i=a; i<n; ++i) # define bug puts("H"); # define lch p<<1,l,mid # define rch p<<1|1,mid+1,r # pragma comment(linker, "/STACK:1024000000,1024000000") typedef long long LL; typedef unsigned long long ULL; int _MAX(int a, int b){return a>b?a:b;} int _MIN(int a, int b){return a>b?b:a;} int Scan() { int res=0, flag=0; char ch; if((ch=getchar())==‘-‘) flag=1; else if(ch>=‘0‘&&ch<=‘9‘) res=ch-‘0‘; while((ch=getchar())>=‘0‘&&ch<=‘9‘) res=res*10+(ch-‘0‘); return flag?-res:res; } void Out(int a) { if(a<0) {putchar(‘-‘); a=-a;} if(a>=10) Out(a/10); putchar(a%10+‘0‘); } LL a[100005][2]; LL dis(LL x1, LL y1, LL x2, LL y2) { return (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1); } int main () { LL n, px, py, ma=0; double mi=1e16; scanf("%lld%lld%lld",&n,&px,&py); FOR(i,1,n) { scanf("%lld%lld",&a[i][0],&a[i][1]); LL d = dis(a[i][0],a[i][1],px,py); mi=min(mi,(double)d); ma=max(ma,d); } a[n+1][0]=a[1][0], a[n+1][1]=a[1][1]; FOR(i,1,n) { LL A2=dis(px,py,a[i][0],a[i][1]); LL B2=dis(px,py,a[i+1][0],a[i+1][1]); LL C2=dis(a[i][0],a[i][1],a[i+1][0],a[i+1][1]); double A=sqrt(A2), B=sqrt(B2), C=sqrt(C2); if (C2+B2>A2&&C2+A2>B2) { double P=(A+B+C)/2; double S=sqrt(P*(P-A)*(P-B)*(P-C)); double H=S/C*2; mi=min(mi,H*H); } } printf("%.10lf\n",pi*(ma-mi)); return 0; }
B.Skills(贪心+枚举+二分)
给你n个数,可以花费1使得数字+1,最大加到A,最多花费m。最后,n个数里的最小值为min,为A的有k个,给你cm和cf,求force=min*cm+k*cf 的最大值,和n个数操作后的结果。
我们如果要让最小值增加,那它加到和第二小的一样时,就有两个最小值,接下来就要两个一起增加。到后来就要好多个一起增加了。
那么我们可以枚举加到A的有多少个,然后用二分的方法求剩下m元,可以使最小值最大为多少。
#include<bits/stdc++.h> #define N 100005 #define ll long long using namespace std; struct data { ll id,v; } a[N]; bool cmp(data a,data b) { return a.v<b.v||a.v==b.v&&a.id<b.id; } ll n,A,cf,cm,m; ll L,ans[N],f,ansA,ansL; ll s[N]; ll findL(ll m,ll R)//还剩多少m,右端点是什么 { ll l=0,r=A,ans=0;//二分确定最小值的值 while(l<=r) { ll mid=(r+l)>>1; //二分确定有多少个比这个值小,然后计算需要的花费 int p=lower_bound(a+1,a+1+n,(data){0,mid},cmp)-a-1; if(p>R)p=R; if(p*mid-s[p]<=m) { ans=mid; l=mid+1; } else r=mid-1; } return ans; } int main() { scanf("%lld%lld%lld%lld%lld",&n,&A,&cf,&cm,&m); for(int i=1; i<=n; i++) { scanf("%lld",&a[i].v); a[i].id=i; } sort(a+1,a+n+1,cmp);//先排序再求前缀和 for(int i=1; i<=n; i++) s[i]=s[i-1]+a[i].v; for(int i=0; i<=n; i++) //如果有i个设置为A的话 { ll p=A*i-s[n]+s[n-i];//花费 if(p<=m) { L=findL(m-p,n-i);//那最小值可以达到多少 if(cm*L+cf*i>f) //更新答案 { f=cm*L+cf*i; ansA=i;//储存有几个变成A ansL=L;//储存最小值要达到多少 } } } printf("%lld\n",f); for(int j=1; j<=n; j++) { if(j>n-ansA) ans[a[j].id]=A; else if(a[j].v<=ansL) ans[a[j].id]=ansL; else ans[a[j].id]=a[j].v; } for(int i=1; i<=n; i++) printf("%lld ",ans[i]); return 0; }
C.Necklace(构造)
给你n种字符,每种有ai个,构造一个环,要求刨开环之后形成回文串,且种数最多。
显然当ai中有两个奇数,答案为0.
我们可以把这n个字符分成x个部分,且每个部分中每个字符的个数一样。
这样x<=gcd(a1,a2...ai).
我们证明答案一定能取到gcd(a1,a2...ai).
首先如果ai中有一个奇数,我们可以令每个部分都形成一个回文串。
如果ai中没有奇数,我们可以令每个部分与相邻的部分成为一个回文串。可以证明第一个部分
同样可以与最后一个部分成为回文串。
所以答案就是x
# include <stdio.h> # include <string.h> # include <stdlib.h> # include <iostream> # include <vector> # include <queue> # include <stack> # include <map> # include <math.h> # include <algorithm> using namespace std; # define lowbit(x) ((x)&(-x)) # define pi acos(-1.0) # define MAXN 100005 # define eps 1e-5 # define MAXM 1000005 # define MOD 1000000007 # define INF 1000000000 # define mem(a,b) memset(a,b,sizeof(a)) # define FOR(i,a,n) for(int i=a; i<=n; ++i) # define FO(i,a,n) for(int i=a; i<n; ++i) # define bug puts("H"); # define lch p<<1,l,mid # define rch p<<1|1,mid+1,r # pragma comment(linker, "/STACK:1024000000,1024000000") typedef long long LL; typedef unsigned long long ULL; int _MAX(int a, int b){return a>b?a:b;} int _MIN(int a, int b){return a>b?b:a;} int Scan() { int res=0, flag=0; char ch; if((ch=getchar())==‘-‘) flag=1; else if(ch>=‘0‘&&ch<=‘9‘) res=ch-‘0‘; while((ch=getchar())>=‘0‘&&ch<=‘9‘) res=res*10+(ch-‘0‘); return flag?-res:res; } void Out(int a) { if(a<0) {putchar(‘-‘); a=-a;} if(a>=10) Out(a/10); putchar(a%10+‘0‘); } int a[30]; int gcd(int x, int y){y==0?x:gcd(y,x%y);} int main () { int n, cnt=0; scanf("%d",&n); FOR(i,1,n) scanf("%d",a+i), cnt+=a[i]&1; int G=a[1]; FOR(i,2,n) G=gcd(G,a[i]); if (n==1) { printf("%d\n",a[1]); FOR(i,1,a[1]) putchar(‘a‘); putchar(‘\n‘); return 0; } if (cnt>=2) { puts("0"); FOR(i,1,n) FOR(j,1,a[i]) putchar(‘a‘+i-1); putchar(‘\n‘); } else if (cnt==1) { printf("%d\n",G); FOR(k,1,G) { FOR(i,1,n) if (a[i]%2==0) FOR(j,1,a[i]/G/2) putchar(‘a‘+i-1); FOR(i,1,n) if (a[i]&1) FOR(j,1,a[i]/G) putchar(‘a‘+i-1); for (int i=n; i>=1; --i) if (a[i]%2==0) FOR(j,1,a[i]/G/2) putchar(‘a‘+i-1); } } else { printf("%d\n",G); FOR(k,1,G/2) { FOR(i,1,n) FOR(j,1,a[i]/G) putchar(‘a‘+i-1); for (int i=n; i>=1; --i) FOR(j,1,a[i]/G) putchar(‘a‘+i-1); } putchar(‘\n‘); } return 0; }
D.Kingdom and its Cities(虚树)
题意:给出n个节点的树,询问q次,每次询问mi个点,问将这mi个点分离开来
至少需要割掉多少个点。
(n<=1e5,sigma(mi)<=1e5)
显然无解的情况是存在两个点相邻。
我们先来考虑每次询问。从树的底层往高层看,
如果一个节点是询问点,那么它的子树中有询问点的就删掉它的子树。
如果一个节点是非询问点,那么它的有询问点的子树超过1个的时候,
就需要把这个节点为根的树给删了。
所以一遍dfs即可。复杂度O(n).对于q个询问,复杂度O(n*q).
因为sigma(mi)<=1e5.
我们把询问点单独拉出来建立一颗虚树。
复杂度O((n+sigma(m))*logn).
# include <stdio.h> # include <string.h> # include <stdlib.h> # include <iostream> # include <vector> # include <queue> # include <stack> # include <map> # include <math.h> # include <algorithm> using namespace std; # define lowbit(x) ((x)&(-x)) # define pi acos(-1.0) # define MAXN 100005 # define eps 1e-5 # define MAXM 500001 # define MOD 1000000007 # define INF 1000000000 # define mem(a,b) memset(a,b,sizeof(a)) # define FOR(i,a,n) for(int i=a; i<=n; ++i) # define FO(i,a,n) for(int i=a; i<n; ++i) # define bug puts("H"); typedef long long LL; typedef unsigned long long ULL; int _MAX(int a, int b){return a>b?a:b;} int _MIN(int a, int b){return a>b?b:a;} int Scan() { int res=0, flag=0; char ch; if((ch=getchar())==‘-‘) flag=1; else if(ch>=‘0‘&&ch<=‘9‘) res=ch-‘0‘; while((ch=getchar())>=‘0‘&&ch<=‘9‘) res=res*10+(ch-‘0‘); return flag?-res:res; } void Out(int a) { if(a<0) {putchar(‘-‘); a=-a;} if(a>=10) Out(a/10); putchar(a%10+‘0‘); } struct Edge{int p, next;}edge[MAXN<<1]; int head[MAXN], cnt=1, mark, top, ans; int bin[20], dep[MAXN], id[MAXN], fa[MAXN][20], h[MAXN], st[MAXN], vis[MAXN]; bool comp(int a, int b){return id[a]<id[b];} void bin_init(){bin[0]=1; FO(i,1,20) bin[i]=bin[i-1]<<1;} void add_edge(int u, int v) { if (u==v) return ; edge[cnt].p=v; edge[cnt].next=head[u]; head[u]=cnt++; } void dfs(int x, int fat) { id[x]=++mark; fa[x][0]=fat; for (int i=1; bin[i]<=dep[x]; ++i) fa[x][i]=fa[fa[x][i-1]][i-1]; for (int i=head[x]; i; i=edge[i].next) { int v=edge[i].p; if (v==fat) continue; dep[v]=dep[x]+1; dfs(v,x); } } int dp_dfs(int x) { if (vis[x]) { for (int i=head[x]; i; i=edge[i].next) { int v=edge[i].p; if (dp_dfs(v)) ans++; } head[x]=vis[x]=0; return 1; } else { int tot=0; for (int i=head[x]; i; i=edge[i].next) { int v=edge[i].p; tot+=dp_dfs(v); } head[x]=vis[x]=0; if (tot>1) {ans++; return 0;} else return tot; } } int lca(int x, int y) { if (dep[x]<dep[y]) swap(x,y); int t=dep[x]-dep[y]; for (int i=0; bin[i]<=t; ++i) if (bin[i]&t) x=fa[x][i]; if (x==y) return x; for (int i=19; i>=0; --i) if (fa[x][i]!=fa[y][i]) x=fa[x][i], y=fa[y][i]; return fa[x][0]; } void sol() { int m=Scan(); cnt=1; top=0, ans=0; FOR(i,1,m) h[i]=Scan(), vis[h[i]]=1; sort(h+1,h+m+1,comp); FOR(i,2,m) if (vis[fa[h[i]][0]]) { puts("-1"); FOR(i,1,m) vis[h[i]]=0; return ; } st[++top]=1; int P=h[1]==1?2:1; FOR(i,P,m) { int f=lca(h[i],st[top]); while (dep[f]<dep[st[top-1]]) add_edge(st[top-1],st[top]), top--; add_edge(f,st[top--]); if (f!=st[top]) st[++top]=f; st[++top]=h[i]; } while (top>1) add_edge(st[top-1],st[top]), top--; dp_dfs(1); printf("%d\n",ans); } int main () { bin_init(); int n, q, u, v; n=Scan(); FO(i,1,n) u=Scan(), v=Scan(), add_edge(u,v), add_edge(v,u); dfs(1,0); q=Scan(); mem(head,0); while (q--) sol(); return 0; }
E.Puzzle Lover(待填坑)