cf Round 594
A.Warrior and Archer(思维)
战士一定会ban掉当前边缘的位置。而战士和射手就会选择剩下的最远的两点。
我们让剩下的最远的两点最近就达到了均衡。
于是我们枚举战士ban掉的边缘,ban的次数是一定的。
# include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # include <vector> # include <queue> # include <stack> # include <map> # include <set> # include <cmath> # include <algorithm> using namespace std; # define lowbit(x) ((x)&(-x)) # define pi acos(-1.0) # define eps 1e-3 # 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 # define mp make_pair # define pb push_back typedef pair<int,int> PII; typedef vector<int> VI; # pragma comment(linker, "/STACK:1024000000,1024000000") typedef long long LL; 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'); } const int N=200005; //Code begin... int a[N]; int main () { int n; scanf("%d",&n); FOR(i,1,n) scanf("%d",a+i); sort(a+1,a+n+1); int ans=INF; int k=n-(n-2)/2; FOR(i,1,n+1-k) ans=min(ans,a[i+k-1]-a[i]); printf("%d\n",ans); return 0; }
B.Max and Bike(二分)
二分时间t,然后用控制精度check就行了。关键是这题的单调性不明显。
另外用fabs控制精度不行,浮点数误差。。。以后就控制二分次数吧。
# include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # include <vector> # include <queue> # include <stack> # include <map> # include <set> # include <cmath> # include <algorithm> using namespace std; # define lowbit(x) ((x)&(-x)) # define pi acos(-1.0) # define eps 1e-7 # 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 # define mp make_pair # define pb push_back typedef pair<int,int> PII; typedef vector<int> VI; # pragma comment(linker, "/STACK:1024000000,1024000000") typedef long long LL; 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'); } const int N=100005; //Code begin... int n; double s, f, r, v; bool check(double t) { double S=v*t, l=2*pi*r; double ss=S-floor(S/l)*l; double T=S+fabs(sin(ss/2/r))*2*r; return T>=f-s; } int main () { scanf("%d%lf%lf",&n,&r,&v); while (n--) { scanf("%lf%lf",&s,&f); double l=0, r=1e12; int tot=100; while (tot--) { double mid=(l+r)/2; if (check(mid)) r=mid; else l=mid; } printf("%.7lf\n",l); } return 0; }
C.Edo and Magnets(贪心)
求平面n个点至多减少k个点后,用一个矩形覆盖它们,求这个矩形面积的最小值。(k<=10)
显然把边界的点先减掉最好,于是我们枚举四个边界上的点减少多少个后更新答案就ok了。
# include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # include <vector> # include <queue> # include <stack> # include <map> # include <set> # include <cmath> # include <algorithm> using namespace std; # define lowbit(x) ((x)&(-x)) # define pi acos(-1.0) # define eps 1e-3 # 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 # define mp make_pair # define pb push_back typedef pair<int,int> PII; typedef vector<int> VI; # pragma comment(linker, "/STACK:1024000000,1024000000") typedef long long LL; 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'); } const int N=100005; //Code begin... struct node{int x, y;}p[N]; bool cmp1(int a,int b){return p[a].x<p[b].x;} bool cmp2(int a,int b){return p[a].x>p[b].x;} bool cmp3(int a,int b){return p[a].y<p[b].y;} bool cmp4(int a,int b){return p[a].y>p[b].y;} int pos1[N], pos2[N], pos3[N], pos4[N], last[N]; int main() { int n, k; scanf("%d%d",&n,&k); FO(i,0,n) { int x1,y1,x2,y2; scanf("%d%d%d%d",&x1,&y1,&x2,&y2); p[i].x=(x1+x2); p[i].y=(y1+y2); pos1[i]=pos2[i]=pos3[i]=pos4[i]=i; } sort(pos1,pos1+n,cmp1); sort(pos2,pos2+n,cmp2); sort(pos3,pos3+n,cmp3); sort(pos4,pos4+n,cmp4); int now=0; LL ans = 1LL<<62; FOR(a,0,k) FOR(b,0,k) FOR(c,0,k) FOR(d,0,k) { now++; int cnt = 0; FO(i,0,a) if(last[pos1[i]]!=now) last[pos1[i]]=now,cnt++; FO(i,0,b) if(last[pos2[i]]!=now) last[pos2[i]]=now,cnt++; FO(i,0,c) if(last[pos3[i]]!=now) last[pos3[i]]=now,cnt++; FO(i,0,d) if(last[pos4[i]]!=now) last[pos4[i]]=now,cnt++; if(cnt!=k) continue; LL Maxx=-1LL<<62,Maxy=-1LL<<62,Minx=1LL<<62,Miny=1LL<<62; FO(i,0,n) { if(last[i]!=now) { Maxx=max(Maxx,p[i].x*1LL); Minx=min(Minx,p[i].x*1LL); Maxy=max(Maxy,p[i].y*1LL); Miny=min(Miny,p[i].y*1LL); } } LL x=Maxx-Minx, y=Maxy-Miny; x=max(x,2LL); y=max(y,2LL); ans=min(ans,x*y); } printf("%lld\n",ans/4); }
D.REQ(BIT+积性函数+逆元)
询问区间积[l,r]的欧拉函数。n,q<=2e5,ai<=1e6
因为欧拉函数是积性函数,我们化解一下式子,把不同的素因子拿出来维护一下就行了。
离散化后用树状数组离线处理区间[l,r]内的不同质因子,类似于HH的项链。
之后求答案的时候用逆元搞搞就行了。
# include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # include <vector> # include <queue> # include <stack> # include <map> # include <set> # include <cmath> # include <algorithm> using namespace std; # define lowbit(x) ((x)&(-x)) # define pi acos(-1.0) # define eps 1e-3 # 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 # define mp make_pair # define pb push_back typedef pair<int,int> PII; typedef vector<int> VI; # pragma comment(linker, "/STACK:1024000000,1024000000") typedef long long LL; 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'); } const int N=200005; //Code begin... typedef struct{int l, r, id;}Node; Node qq[N]; int a[N], pri[N*11], n; LL sum[N], isum[N], mul[N], imul[N], tree[N], res[N]; queue<int> to[N]; map<int, int> vis; VI vc[N]; void get_prim() { FOR(i,2,2020000) { if (!pri[i]) pri[++pri[0]]=i, vis[i]=pri[0]; for (int j=1; j<=pri[0]&&pri[j]<=2020000/i; ++j) { pri[pri[j]*i]=1; if (i%pri[j]==0) break; } } } bool comp(Node a, Node b){return a.l<b.l;} LL inv(LL a, LL m){ if (a==1) return 1; return inv(m%a,m)*(m-m/a)%m; } void add(int x, LL val) { while (x<=n) tree[x]=tree[x]*val%MOD, x+=lowbit(x); } LL query(int x) { LL ans=1; while (x) ans=ans*tree[x]%MOD, x-=lowbit(x); return ans; } int main () { get_prim(); FO(i,1,pri[0]) mul[i]=(LL)(pri[i]-1)*inv(pri[i],MOD)%MOD, imul[i]=(LL)pri[i]*inv(pri[i]-1,MOD)%MOD; int q; n=Scan(); FOR(i,1,n) tree[i]=1; sum[0]=isum[0]=1; FOR(i,1,n) { a[i]=Scan(), sum[i]=sum[i-1]*a[i]%MOD, isum[i]=isum[i-1]*inv(a[i],MOD)%MOD; int temp=a[i]; for (int j=1; pri[j]*pri[j]<=temp; ++j) { if (temp%pri[j]==0) { to[j].push(i), vc[i].pb(j), temp/=pri[j]; while (temp%pri[j]==0) temp/=pri[j]; } } if (temp>1) to[vis[temp]].push(i), vc[i].pb(vis[temp]); } q=Scan(); FOR(i,1,q) qq[i].l=Scan(), qq[i].r=Scan(), qq[i].id=i; sort(qq+1,qq+q+1,comp); FO(i,1,pri[0]) if (!to[i].empty()) add(to[i].front(),mul[i]); int now=1; FOR(i,1,q) { while (now<qq[i].l) { int size=vc[now].size(); for (int j=0; j<size; ++j) { int k=vc[now][j]; add(to[k].front(),imul[k]), to[k].pop(); if (!to[k].empty()) add(to[k].front(),mul[k]); } now++; } res[qq[i].id]=sum[qq[i].r]*isum[qq[i].l-1]%MOD*query(qq[i].r)%MOD; } FOR(i,1,q) printf("%lld\n",res[i]); return 0; }
E.Cutting the Line(待填坑)