Educational Codeforces Round 87
https://codeforces.com/contest/1354
水题略过,从C开始。
1354C 1354D 1354E 1354F
C2. Not So Simple Polygon Embedding
记 A 为边对中心的角度的一半,即 0.5 对应角度
A= pi/(2*n)
以六边形为例,简单套个矩形结果是长方形: 1/tan(A) & 1/sin(A)
但是我们要的是正方形,所以需要转动角度 B (由于对称性可以设 0<=B<=A/2 )
如果猜对称,可以猜出 B=A/2,但不确定的话就只好算算了
1/tan(A) -> cos(A-B)/sin(A)
1/sin(A) -> cos(B)/sin(A)
发现只有 B=A/2这一个解,边长 cos(A/2)/sin(A) = 0.5/sin(A/2)
#include<bits/stdc++.h>
using namespace std;
const double pi=acos(-1.0);
int main() {int t;
cin>>t;
while(t--) {
int n;
scanf("%d",&n);
printf("%.8lf\n",0.5/sin(pi/(4*n)));
}
}
D. Multiset
很坑输入时间,注意scanf起步,getchar更好
可以用BIT 纪录 1-n 内每个数的个数,在BIT O(log(n)) 区间和的基础上,补充一个二分查找可以O(log2(n))找到第K数,这样就可以过了
但使用BIT把O(log2(n))变成O(log(n))也是可以的。
注意一般的二分查找,每查一步,求新的区间和需要 O(log(n))
但是BIT有个特点,对于p>q>=0, d[2^p+2^q] 存储了 [2^p+1,2^p+2^q] 区间的和
如果你上一步查过 1到2^p的区间和, 现在查 1到(2^p+2^q) 其实只需要把之前的结果加上 d[2^p+2^q]就行
#include<bits/stdc++.h> using namespace std; template<typename T> class BItree { public: unsigned sz; T* d; BItree(unsigned n) { sz=n+1; d=new T[sz] {}; } ~BItree(){ delete[] d; } inline void add(unsigned p,T num) { while(p<sz) { d[p]+=num; p+=p&(-p); } } inline T getsum(unsigned p) { T sum=0; while(p) { sum+=d[p]; p&=p-1; } return sum; } }; int main() { int n,q,m,x; scanf("%d%d",&n,&q); for(m=1;m*2<=n;m*=2); BItree<int> a(n+1); for(int i=0;i<n;++i){ scanf("%d",&x); a.add(x,1); } for(int i=0;i<q;++i){ scanf("%d",&x); if(x>0) a.add(x,1); else{ x=-x; int ans=0; for(int step=m;step;step>>=1){ if(ans+step<=n&&a.d[ans+step]<x){ x-=a.d[ans+step]; ans+=step; } } a.add(ans+1,-1); } } for(int i=1;i<=n;++i){ if(a.d[i]){ cout<<i<<endl; return 0; } } cout<<0<<endl; }
E. Graph Coloring
很容易发现,可以无视 label 3 与 label 1 的区别,最后(如果)需要输出节点label 的时候,把前n3个'1' 改成 '3' 就行。
先考虑一个连通块blocks[bi],有如下3 种情况:
1. 没有办法
直接NO
2. 把序号最小的节点标为 1, 然后一路用212...标完
一边标一边计数,有 blocks[bi][1] 个节点表了 1, blocks[bi][2] 个标了 2.
3. 把序号最小的节点标为 2, 然后一路用121...标完
刚好与2.的情况相反,无需再算
现在我们对每个联通块得到了结论:要么在这里标 blocks[bi][1] 个 '1', 要么标 blocks[bi][2] 个 ’1‘
又,一共要有 n1+n3 个 ’1‘
具体解决可以看代码吧
#include<bits/stdc++.h> using namespace std; const int N=5004,M=100004; vector<int> nbr[N]; int value[N]={}; bool fail=false; int blocks[N][3]={},bi=0,block_of[N]; int bflip[N]; void grow_block(int id,int v){ //cout<<id<<" "<<v<<"\t"; if(fail) return; value[id]=v; ++blocks[bi][v]; block_of[id]=bi; for(int i=0;i<nbr[id].size();++i){ if(value[nbr[id][i]]==0){ grow_block(nbr[id][i],v^3); }else if(value[nbr[id][i]]==v){ //cout<<"FAIL at "<<id<<" "<<nbr[id][i]<<endl; fail=true; return; } } } bool get_block_choice(int i,int left){ static char mem[N][N]; if(left<0) return false; if(i==bi) return left==0; if(mem[i][left]) return mem[i][left]=='Y'; if(get_block_choice(i+1,left-blocks[i][1])){ bflip[i]=0; mem[i][left]='Y'; }else if(get_block_choice(i+1,left-blocks[i][2])){ bflip[i]=3; mem[i][left]='Y'; }else{ mem[i][left]='N'; return false; } return true; } int main() { int n,n1,n2,n3,m; int a,b; scanf("%d%d%d%d%d",&n,&m,&n1,&n2,&n3); for(int i=0;i<m;++i){ scanf("%d%d",&a,&b); nbr[a].push_back(b); nbr[b].push_back(a); } /*for(int i=1;i<=n;++i){ cout<<i<<": "; for(int j=0;j<nbr_size[i];++j){ cout<<nbr[i][j]<<" "; } cout<<endl; }*/ for(int i=1;i<=n;++i){ if(value[i]) continue; //cout<<"\nblock "<<bi<<":"<<endl; grow_block(i,1); //cout<<"\nNode 1: "<<blocks[bi][1]<<"\tNode 2: "<<blocks[bi][2]<<endl; ++bi; if(fail){ puts("NO"); return 0; } } if(!get_block_choice(0,n1+n3)){ puts("NO"); return 0; } puts("YES"); for(int i=1;i<=n;++i){ int out=(value[i]^bflip[block_of[i]])+'0'; if(out=='1'&&n3){ --n3; out='3'; } putchar(out); } puts(""); }
F. Summoning Minions
分为两组mimions:
1. 保留至最后, k个位置, 第i个贡献 a+b(i-1)
2. 上场退场buff机 贡献 b(k-1)
注意1中的b是降序,所以可以排序+DP
#include <bits/stdc++.h> using namespace std; struct Mn { int b,a,id; } mn[100]; int dp[80][80]; int main() { ios::sync_with_stdio(false); int T; cin>>T; while(T--) { int n,k; cin>>n>>k; for(int i=1; i<=n; ++i) { cin>>mn[i].a>>mn[i].b; mn[i].id=i; } sort(mn+1,mn+n+1,[](const Mn& x,const Mn& y) { return x.b<y.b; }); for(int i=0; i<=n; ++i) { for(int j=0; j<=k; ++j) { dp[i][j]=-1000000000; } } dp[0][0]=0; for(int i=1; i<=n; ++i) { int a=mn[i].a, b=mn[i].b; dp[i][0]=dp[i-1][0]+(k-1)*b; for(int j=1; j<=k&&j<=i; ++j) { dp[i][j]=max(dp[i-1][j]+(k-1)*b, dp[i-1][j-1]+a+b*(j-1)); } } vector<int> ans1,ans2; for(int x=n,y=k; x>0; --x) { if(y>0&&dp[x][y]==dp[x-1][y-1]+mn[x].a+mn[x].b*(y-1)) { --y; ans1.push_back(mn[x].id); } else { ans2.push_back(mn[x].id); } } cout<<ans1.size()+2*ans2.size()<<endl; for(int i=ans1.size()-1; i>0; --i) cout<<ans1[i]<<" "; for(int i=ans2.size()-1; i>=0; --i) cout<<ans2[i]<<" "<<-ans2[i]<<" "; cout<<ans1[0]<<endl; } return 0; }

浙公网安备 33010602011771号