A - You're in the Army Now
贪心。我们直接将这些人按分数从大到小排序,然后按照这个顺序让他们选择,最后按照要求输出即可。但是输出的排序方式不是字典序,而是字母序,这里要注意。
1 #include<cstdio> 2 #include<algorithm> 3 #include<iostream> 4 #include<vector> 5 #include<sstream> 6 const int N=1e5+5; 7 int n,m,k,a[N]; 8 std::string s[N]; 9 std::vector<std::string> g[N]; 10 std::vector<int> e[N]; 11 int t[N],b[N]; 12 bool cmp(int x,int y) { 13 return b[x]>b[y]; 14 } 15 bool cmp2(const std::string &a,const std::string &b) { 16 int len=std::min(a.length(),b.length()); 17 int l,r; 18 for(int i=0;i<len;i++) { 19 if(a[i]==b[i]) continue; 20 if(a[i]==' '&&b[i]!=' ') return true; 21 if(a[i]!=' '&&b[i]==' ') return false; 22 if(a[i]>='a') l=a[i]-'a'; 23 else l=a[i]-'A'; 24 if(b[i]>='a') r=b[i]-'a'; 25 else r=b[i]-'A'; 26 if(l!=r) return l<r; 27 else return a[i]<b[i]; 28 } 29 return a.length()<b.length(); 30 } 31 int main() { 32 freopen("army.in","r",stdin); 33 freopen("army.out","w",stdout); 34 std::cin>>n>>m>>k; 35 for(int i=1;i<=m;i++) std::cin>>a[i]; 36 std::string x; 37 std::getline(std::cin,x); 38 std::stringstream f; 39 for(int i=1;i<=n;i++) { 40 std::getline(std::cin,x); 41 int p=0; 42 for(int i=1;i<x.length();i++) { 43 if(x[i]>='0'&&x[i]<='9') { 44 p=i; 45 break; 46 } 47 } 48 s[i]=x.substr(0,p); 49 while(s[i].back()==' ') s[i].pop_back(); 50 x=x.substr(p); 51 p=0; 52 while(s[i][p]==' ') p++; 53 s[i]=s[i].substr(p); 54 int k,z;f.clear();f<<x; 55 f>>b[i]>>k; 56 while(k--) { 57 f>>z; 58 e[i].push_back(z); 59 } 60 t[i]=i; 61 } 62 std::sort(t+1,t+1+n,cmp); 63 for(int i=1;i<=n;i++) { 64 int u=t[i]; 65 for(int v:e[u]) { 66 if(a[v]>0) { 67 --a[v]; 68 g[v].push_back(s[u]); 69 break; 70 } 71 } 72 } 73 for(int i=1;i<=m;i++) { 74 if(i>1) printf("\n"); 75 std::sort(g[i].begin(),g[i].end(),cmp2); 76 for(auto &w:g[i]) std::cout<<w<<std::endl; 77 } 78 return 0; 79 }
C - Ballistic
高斯消元。题目其实很明确,求解题目所述行列式即可。但是该行列式有未知数,我们无法方便的求解,但题目已经告诉我们,该多项式是个$n+1$次多项式,不妨我们用待定系数法,设该多项式为$f(\lambda)=\sum_{i=0}^na_i\lambda^{i}$,如果我们能分别计算出$\lambda=[1,n+1]$这个范围内的所有的值,那么我们就可以利用高斯消元求出这些系数。而求解一个特定的$\lambda$的值,也很容易,可以把值代入原行列式进行求解。当然,这都是理论方法,实际上,系数会特别大,所以需要大数,这里有个技巧,可以选取一些质数,让他们的乘积足够大,然后在这些质数的模意义下求行列式以及高斯消元,最后中国剩余定理合并。
1 #include<iostream> 2 #include<vector> 3 #include<cstdio> 4 #include<cassert> 5 #include<cstring> 6 typedef long long ll; 7 8 struct BigInteger { 9 typedef unsigned long long LL; 10 static const int BASE = 100000000; 11 static const int WIDTH = 8; 12 std::vector<int> s; 13 14 BigInteger& clean(){while(!s.back()&&s.size()>1)s.pop_back(); return *this;} 15 BigInteger(LL num = 0) {*this = num;} 16 BigInteger(std::string s) {*this = s;} 17 BigInteger& operator = (long long num) { 18 s.clear(); 19 do { 20 s.push_back(num % BASE); 21 num /= BASE; 22 } while (num > 0); 23 return *this; 24 } 25 BigInteger& operator = (const std::string& str) { 26 s.clear(); 27 int x, len = (str.length() - 1) / WIDTH + 1; 28 for (int i = 0; i < len; i++) { 29 int end = str.length() - i*WIDTH; 30 int start = std::max(0, end - WIDTH); 31 sscanf(str.substr(start,end-start).c_str(), "%d", &x); 32 s.push_back(x); 33 } 34 return (*this).clean(); 35 } 36 37 BigInteger operator + (const BigInteger& b) const { 38 BigInteger c; c.s.clear(); 39 for (int i = 0, g = 0; ; i++) { 40 if (g == 0 && i >= s.size() && i >= b.s.size()) break; 41 int x = g; 42 if (i < s.size()) x += s[i]; 43 if (i < b.s.size()) x += b.s[i]; 44 c.s.push_back(x % BASE); 45 g = x / BASE; 46 } 47 return c; 48 } 49 BigInteger operator - (const BigInteger& b) const { 50 assert(b <= *this); 51 BigInteger c; c.s.clear(); 52 for (int i = 0, g = 0; ; i++) { 53 if (g == 0 && i >= s.size() && i >= b.s.size()) break; 54 int x = s[i] + g; 55 if (i < b.s.size()) x -= b.s[i]; 56 if (x < 0) {g = -1; x += BASE;} else g = 0; 57 c.s.push_back(x); 58 } 59 return c.clean(); 60 } 61 BigInteger operator * (const BigInteger& b) const { 62 int i, j; LL g; 63 std::vector<LL> v(s.size()+b.s.size(), 0); 64 BigInteger c; c.s.clear(); 65 for(i=0;i<s.size();i++) for(j=0;j<b.s.size();j++) v[i+j]+=LL(s[i])*b.s[j]; 66 for (i = 0, g = 0; ; i++) { 67 if (g ==0 && i >= v.size()) break; 68 LL x = v[i] + g; 69 c.s.push_back(x % BASE); 70 g = x / BASE; 71 } 72 return c.clean(); 73 } 74 BigInteger operator / (const BigInteger& b) const { 75 assert(b > 0); 76 BigInteger c = *this; 77 BigInteger m; 78 for (int i = s.size()-1; i >= 0; i--) { 79 m = m*BASE + s[i]; 80 c.s[i] = bsearch(b, m); 81 m -= b*c.s[i]; 82 } 83 return c.clean(); 84 } 85 BigInteger operator % (const BigInteger& b) const { 86 BigInteger c = *this; 87 BigInteger m; 88 for (int i = s.size()-1; i >= 0; i--) { 89 m = m*BASE + s[i]; 90 c.s[i] = bsearch(b, m); 91 m -= b*c.s[i]; 92 } 93 return m; 94 } 95 96 int bsearch(const BigInteger& b, const BigInteger& m) const{ 97 int L = 0, R = BASE-1, x; 98 while (1) { 99 x = (L+R)>>1; 100 if (b*x<=m) {if (b*(x+1)>m) return x; else L = x;} 101 else R = x; 102 } 103 } 104 BigInteger& operator += (const BigInteger& b) {*this = *this + b; return *this;} 105 BigInteger& operator -= (const BigInteger& b) {*this = *this - b; return *this;} 106 BigInteger& operator *= (const BigInteger& b) {*this = *this * b; return *this;} 107 BigInteger& operator /= (const BigInteger& b) {*this = *this / b; return *this;} 108 BigInteger& operator %= (const BigInteger& b) {*this = *this % b; return *this;} 109 110 bool operator < (const BigInteger& b) const { 111 if (s.size() != b.s.size()) return s.size() < b.s.size(); 112 for (int i = s.size()-1; i >= 0; i--) 113 if (s[i] != b.s[i]) return s[i] < b.s[i]; 114 return false; 115 } 116 bool operator >(const BigInteger& b) const{return b < *this;} 117 bool operator<=(const BigInteger& b) const{return !(b < *this);} 118 bool operator>=(const BigInteger& b) const{return !(*this < b);} 119 bool operator!=(const BigInteger& b) const{return b < *this || *this < b;} 120 bool operator==(const BigInteger& b) const{return !(b < *this) && !(b > *this);} 121 }; 122 123 std::ostream& operator << (std::ostream& out, const BigInteger& x) { 124 out << x.s.back(); 125 for (int i = x.s.size()-2; i >= 0; i--) { 126 char buf[20]; 127 sprintf(buf, "%08d", x.s[i]); 128 for (int j = 0; j < strlen(buf); j++) out << buf[j]; 129 } 130 return out; 131 } 132 133 std::istream& operator >> (std::istream& in, BigInteger& x) { 134 std::string s; 135 if (!(in >> s)) return in; 136 x = s; 137 return in; 138 } 139 ll qpow(ll x,ll y,ll mod) { 140 ll res=1; 141 for(;y;y>>=1,x=x*x%mod) if(y&1) res=res*x%mod; 142 return res; 143 } 144 struct CRT { 145 const static int N=1e5+5; 146 std::vector<int> prime; 147 std::vector<int> inv; 148 bool vis[N]; 149 int n; 150 BigInteger mod; 151 void init() { 152 for(int i=2;i<N;i++) if(!vis[i]) { 153 if(i>1e4) prime.push_back(i); 154 for(int j=i+i;j<N;j+=i) vis[j]=true; 155 if(prime.size()>=20) break; 156 } 157 n=prime.size(); 158 inv.clear(); 159 mod=1; 160 for(int i=0;i<n;i++) { 161 ll res=1; 162 mod*=prime[i]; 163 for(int j=0;j<n;j++) if(i!=j) res=res*prime[j]%prime[i]; 164 inv.push_back(int(qpow(res,prime[i]-2,prime[i]))); 165 } 166 //std::cout<<mod<<std::endl; 167 } 168 BigInteger work(const std::vector<int> &g) { 169 BigInteger res=0; 170 for(int i=0;i<n;i++) { 171 res+=mod/prime[i]*inv[i]*g[i]; 172 res%=mod; 173 } 174 return res; 175 } 176 }crt; 177 int solve(std::vector<std::vector<int> > a,int mod) { 178 int n=a.size(); 179 int res=1; 180 for(int i=0;i<n;i++) for(int j=0;j<n;j++) a[i][j]=(a[i][j]%mod+mod)%mod; 181 for(int i=0;i<n;i++) { 182 int r=i; 183 for(;r<n&&!a[r][i];r++); 184 if(r==n) break; 185 if(r!=i) std::swap(a[r],a[i]),res=mod-res; 186 int inv=qpow(a[i][i],mod-2,mod); 187 for(int j=i+1;j<n;j++) { 188 int c=a[j][i]*inv%mod; 189 for(int k=i+1;k<n;k++) a[j][k]=(a[j][k]-c*a[i][k]%mod+mod)%mod; 190 a[j][i]=0; 191 } 192 } 193 for(int j=0;j<n;j++) res=res*a[j][j]%mod; 194 return res; 195 } 196 int main() { 197 freopen("ballistic.in","r",stdin); 198 freopen("ballistic.out","w",stdout); 199 200 crt.init(); 201 int n;scanf("%d",&n); 202 std::vector<std::vector<int> > a(n); 203 for(int i=0;i<n;i++) { 204 a[i].resize(n); 205 for(int j=0;j<n;j++) std::cin>>a[i][j]; 206 } 207 std::vector<std::vector<int> > b(n+1),c; 208 for(int x=0;x<20;x++) { 209 std::vector<std::vector<int> > d; 210 int mod=crt.prime[x]; 211 for(int j=1;j<=n+1;j++) { 212 c=a;std::vector<int> t; 213 for(int k=0;k<n;k++) c[k][k]-=j; 214 int now=1; 215 for(int k=0;k<=n;k++) { 216 t.push_back(now); 217 now=now*j%mod; 218 } 219 t.push_back(solve(c,mod)); 220 d.push_back(t); 221 } 222 for(int i=0;i<=n;i++) { 223 int r=i; 224 for(;r<=n&&!d[r][i];r++); 225 std::swap(d[i],d[r]); 226 int inv=qpow(d[i][i],mod-2,mod); 227 for(int j=0;j<=n;j++) if(i!=j) { 228 int c=d[j][i]*inv%mod; 229 for(int k=i+1;k<=n+1;k++) d[j][k]=(d[j][k]-c*d[i][k]%mod+mod)%mod; 230 d[j][i]=0; 231 } 232 for(int k=i+1;k<=n+1;k++) d[i][k]=d[i][k]*inv%mod; 233 d[i][i]=1; 234 } 235 for(int i=0;i<=n;i++) b[i].push_back(d[i][n+1]); 236 } 237 for(int i=n;~i;i--) { 238 BigInteger res=crt.work(b[i]); 239 if(res>crt.mod/2) { 240 std::cout<<'-'<<crt.mod-res<<std::endl; 241 } 242 else std::cout<<res<<std::endl; 243 } 244 return 0; 245 }
D-保卫萝卜4
他给的凸包是不严格的,我们自己求一下凸包。
这个题数据出的非常垃圾。我们很容易想到对在哪个凸包里进行二分,然后O(这个凸包的点数)暴力判断,但这其实是一种假算法,可以轻松构造两个点数很多的严格凸包,这样复杂度近似mn。所以我觉得这个复杂度不可取。然而它能过。所以我觉得这个题目很垃圾。
另一种两个log的做法我认为才是正解。我们可以O(log凸包点数)来判断一个点是否在凸包内,其实这类似动态凸包的插点过程,我们每次在上下凸壳中找到x坐标大于等于询问点的第一个点,然后直接对这个点,前一个点,询问点 叉积判位置关系即可。
然而因为过于垃圾的数据,这两种做法在时间上竟然没有什么明显差异。
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef double db; 4 const db eps = 1e-6; 5 int sign(db k){if(k>eps)return 1;else if(k<-eps)return -1;return 0;} 6 int cmp(db k1,db k2){return sign(k1-k2);} 7 int inmid(db k1,db k2,db k3){return sign(k1-k3)*sign(k2-k3)<=0;} 8 struct point{ 9 db x,y; 10 point operator + (const point &k1)const {return (point){k1.x+x,k1.y+y};} 11 point operator - (const point &k1)const {return (point){x-k1.x,y-k1.y};} 12 point operator * (db k1)const {return (point){x*k1,y*k1};} 13 point operator / (db k1)const {return (point){x/k1,y/k1};} 14 bool operator < (const point k1) const{ 15 int a=cmp(x,k1.x); 16 if (a==-1) return 1; else if (a==1) return 0; else return cmp(y,k1.y)==-1; 17 } 18 }; 19 db cross(point k1,point k2){return k1.x*k2.y-k1.y*k2.x;} 20 int inmid(point k1,point k2,point q){return inmid(k1.x,k2.x,q.x)&&inmid(k1.y,k2.y,q.y);} 21 int onS(point k1,point k2,point q){return inmid(k1,k2,q)&&sign(cross(k1-q,k2-k1))==0;} 22 db area(vector<point> A){ 23 db ans = 0 ; 24 for(int i=0;i<A.size();i++){//逆时针 25 ans+=cross(A[i],A[(i+1)%A.size()]); 26 } 27 return ans/2; 28 } 29 int contain(vector<point> A,point q){ 30 int pd=0;A.push_back(A[0]); 31 for(int i=1;i<A.size();i++){ 32 point u = A[i-1],v=A[i]; 33 if(onS(u,v,q))return 1;if(cmp(u.y,v.y)>0)swap(u,v); 34 if(cmp(u.y,q.y)>=0||cmp(v.y,q.y)<0)continue; 35 if (sign(cross(u-v,q-v))<0) pd^=1; 36 } 37 return pd<<1; 38 } 39 vector<point> ConvexHull(vector<point>A,int flag=1){ // flag=0 不严格 flag=1 严格 40 int n=A.size(); vector<point>ans(n*2); 41 sort(A.begin(),A.end()); int now=-1; 42 for (int i=0;i<A.size();i++){ 43 while (now>0&&sign(cross(ans[now]-ans[now-1],A[i]-ans[now-1]))<flag) now--; 44 ans[++now]=A[i]; 45 } int pre=now; 46 for (int i=n-2;i>=0;i--){ 47 while (now>pre&&sign(cross(ans[now]-ans[now-1],A[i]-ans[now-1]))<flag) now--; 48 ans[++now]=A[i]; 49 } ans.resize(now); return ans; 50 } 51 int T,n,m; 52 struct nmd{ 53 vector<point> v; 54 db s; 55 }p[100005]; 56 bool cmp2(nmd a,nmd b){ 57 return a.s<b.s; 58 } 59 db S[100005];bool b[100005]; 60 point t; 61 int main(){ 62 freopen("castle.in","r",stdin); 63 freopen("castle.out","w",stdout); 64 scanf("%d",&T); 65 for(int i=1;i<=T;i++){ 66 scanf("%d",&n); 67 for(int j=0;j<n;j++){ 68 scanf("%lf%lf",&t.x,&t.y); 69 p[i].v.push_back(t); 70 } 71 p[i].v=ConvexHull(p[i].v,1); 72 p[i].s=abs(area(p[i].v)); 73 } 74 sort(p+1,p+1+T,cmp2); 75 S[1]=p[1].s; 76 for(int i=2;i<=T;i++){ 77 S[i]=p[i].s-p[i-1].s; 78 } 79 scanf("%d",&m); 80 while (m--){ 81 scanf("%lf%lf",&t.x,&t.y); 82 int l=1,r=T; 83 while (l<=r){ 84 int mid = l+r>>1; 85 if(contain(p[mid].v,t)){ 86 r=mid-1; 87 }else{ 88 l=mid+1; 89 } 90 } 91 b[l]=1; 92 } 93 db ans=0; 94 for(int i=1;i<=T;i++){ 95 if(b[i])ans+=S[i]; 96 } 97 printf("%.6f\n",ans); 98 }
1 #include <cstdio> 2 #include <vector> 3 #include <algorithm> 4 using namespace std; 5 typedef double db; 6 const db eps = 1e-6; 7 inline int sign(db k){if(k>eps)return 1;else if(k<-eps)return -1;return 0;} 8 inline int cmp(db k1,db k2){return sign(k1-k2);} 9 struct point{ 10 db x,y; 11 inline point operator + (const point &k1)const {return (point){k1.x+x,k1.y+y};} 12 inline point operator - (const point &k1)const {return (point){x-k1.x,y-k1.y};} 13 inline point operator * (db k1)const {return (point){x*k1,y*k1};} 14 inline point operator / (db k1)const {return (point){x/k1,y/k1};} 15 inline bool operator < (const point k1) const{ 16 int a=cmp(x,k1.x); 17 if (a==-1) return 1; else if (a==1) return 0; else return cmp(y,k1.y)==-1; 18 } 19 }; 20 inline db cross(point k1,point k2){return k1.x*k2.y-k1.y*k2.x;} 21 inline db area(vector<point> A){ 22 db ans = 0 ; 23 for(int i=0;i<A.size();i++){//逆时针 24 ans+=cross(A[i],A[(i+1)%A.size()]); 25 } 26 return ans/2; 27 } 28 inline void getUDP(vector<point>A,vector<point>&U,vector<point>&D){ 29 db l=1e100,r=-1e100; 30 for (int i=0;i<A.size();i++) l=min(l,A[i].x),r=max(r,A[i].x); 31 int wherel,wherer; 32 for (int i=0;i<A.size();i++) if (cmp(A[i].x,l)==0) wherel=i; 33 for (int i=A.size();i;i--) if (cmp(A[i-1].x,r)==0) wherer=i-1; 34 U.clear(); D.clear(); int now=wherel; 35 while (1){D.push_back(A[now]); if (now==wherer) break; now++; if (now>=A.size()) now=0;} 36 now=wherel; 37 while (1){U.push_back(A[now]); if (now==wherer) break; now--; if (now<0) now=A.size()-1;} 38 } 39 inline bool checkup(vector<point> up,point p){ 40 int m = up.size(); 41 if(p.x<up[0].x||p.x>up[m-1].x)return false;// 42 int id = lower_bound(up.begin(),up.end(),p)-up.begin(); 43 if(p.x==up[id].x){ 44 return p.y<up[id].y; 45 } 46 int pre = id-1; 47 if(cross(up[id]-up[pre],p-up[pre])>0)return false; 48 return true; 49 } 50 inline bool checkdown(vector<point>down,point p){ 51 int m = down.size(); 52 if(p.x<down[0].x||p.x>down[m-1].x)return false; 53 int id = lower_bound(down.begin(),down.end(),p)-down.begin(); 54 if(p.x==down[id].x)return p.y<down[id].y; 55 int pre = id-1; 56 if(cross(down[id]-down[pre],p-down[pre])<0)return false; 57 return true; 58 } 59 vector<point> ConvexHull(vector<point>A,int flag=1){ // flag=0 不严格 flag=1 严格 60 int n=A.size(); vector<point>ans(n*2); 61 sort(A.begin(),A.end()); int now=-1; 62 for (int i=0;i<A.size();i++){ 63 while (now>0&&sign(cross(ans[now]-ans[now-1],A[i]-ans[now-1]))<flag) now--; 64 ans[++now]=A[i]; 65 } int pre=now; 66 for (int i=n-2;i>=0;i--){ 67 while (now>pre&&sign(cross(ans[now]-ans[now-1],A[i]-ans[now-1]))<flag) now--; 68 ans[++now]=A[i]; 69 } ans.resize(now); return ans; 70 } 71 int T,n,m; 72 vector<point> v[100005],up[100005],down[100005]; 73 db s[100005]; 74 inline bool cmp2(int a,int b){ 75 return s[a]<s[b]; 76 } 77 db S[100005];bool b[100005]; 78 int ind[100005]; 79 point t; 80 int main(){ 81 freopen("castle.in","r",stdin); 82 freopen("castle.out","w",stdout); 83 scanf("%d",&T); 84 for(int i=1;i<=T;i++){ 85 ind[i]=i; 86 scanf("%d",&n); 87 for(int j=0;j<n;j++){ 88 scanf("%lf%lf",&t.x,&t.y); 89 v[i].push_back(t); 90 } 91 v[i]=ConvexHull(v[i],1); 92 s[i]=abs(area(v[i])); 93 } 94 for(int i=1;i<=T;i++){ 95 getUDP(v[i],up[i],down[i]); 96 } 97 sort(ind+1,ind+1+T,cmp2); 98 S[1]=s[ind[1]]; 99 for(int i=2;i<=T;i++){ 100 S[i]=s[ind[i]]-s[ind[i-1]]; 101 } 102 scanf("%d",&m); 103 db ans=0; 104 while (m--){ 105 scanf("%lf%lf",&t.x,&t.y); 106 int l=1,r=T; 107 while (l<=r){ 108 int mid = l+r>>1; 109 if(checkdown(down[ind[mid]],t)&&checkup(up[ind[mid]],t)){ 110 r=mid-1; 111 }else{ 112 l=mid+1; 113 } 114 } 115 if(!b[l])ans+=S[l]; 116 b[l]=1; 117 } 118 printf("%.6f\n",ans); 119 }
E - Creeping
状压$dp$。这题直接进行简单的状压$dp$即可,不过需要弄清楚规则,比方说对于打怪的机制,它是伤害和回复一起计算的,也就是说每秒钟掉的血量应该等于怪物的伤害值减去$Uther$的回复值,当然,该值可能为负数。然后还有另一个坑点,就是升级后,$Uther$的生命值也是会发生变化的,会增加两个等级之间最大生命值的差值,但是,这个可能为负数!换句话说,可能$Uther$打怪可以打死,但是升级后可能死亡!最后,题目有说$Uther$不介意打怪时长,故你可以认为它每次打新的怪物时都是满血的。
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 const int N=22,M=105; 5 int dp[1<<20],pre[1<<20]; 6 int n,k; 7 int E[M],H[M],D[M],R[M]; 8 int h[N],d[N],e[N]; 9 int stk[N],top; 10 int main() { 11 freopen("creeping.in","r",stdin); 12 freopen("creeping.out","w",stdout); 13 scanf("%d%d",&n,&k); 14 for(int i=0;i<1<<n;i++) dp[i]=-1,pre[i]=-1; 15 for(int i=1;i<=k;i++) scanf("%d%d%d%d",E+i,H+i,D+i,R+i); 16 for(int i=0;i<n;i++) { 17 scanf("%d%d%d",h+i,d+i,e+i); 18 } 19 dp[0]=H[1]; 20 int ans=0,mask=0; 21 for(int i=0;i<1<<n;i++) if(dp[i]>0) { 22 int tot=0; 23 for(int j=0;j<n;j++) if(i>>j&1) tot+=e[j]; 24 int p=std::upper_bound(E+1,E+1+k,tot)-E-1; 25 for(int j=0;j<n;j++) if(!(i>>j&1)) { 26 long long t=(h[j]+D[p]-1)/D[p]; 27 long long tmp=H[p]-t*(d[j]-R[p]); 28 if(tmp<=0) continue; 29 int rem=std::min(tmp,1LL*H[p]); 30 int now=tot+e[j]; 31 int pp=std::upper_bound(E+1,E+1+k,now)-E-1; 32 rem+=H[pp]-H[p]; 33 if(rem<=0) continue; 34 if(1>dp[i|1<<j]) { 35 dp[i|1<<j]=1; 36 pre[i|1<<j]=j; 37 } 38 } 39 if(tot>ans) { 40 ans=tot; 41 mask=i; 42 } 43 } 44 //printf("%d---\n",dp[2]); 45 printf("%d\n",ans); 46 top=0; 47 while(mask) { 48 stk[top++]=pre[mask]; 49 mask=mask^1<<pre[mask]; 50 } 51 printf("%d\n",top); 52 for(int i=top-1;~i;i--) printf("%d%c",stk[i]+1," \n"[i==0]); 53 return 0; 54 }
G - Princess
签到题。若公主斩断了$k-1$次头发,那么它的头发生长时间就可以分成$k$段,每一段的生长速度互不相同,设第$i$段的时长为$x_i$,则肯定有$\prod_{i=1}^{k}x_i=L$,换句话说,该问题等价于找一些数使得他们的乘积为$L$且和最小,假设我们分成$k$个数,那么,要使得和最小,这$k$个数肯定都是一样的,故,我们等价于求解$f(n)=n*L^{\frac{1}{n}}$的最小值,一个递增的函数乘一个递减的函数,因此我们断定它是一个凸函数,故我们可以三分。当然,还有另一种做法,可以发现,当$n$比较大时,$L^{\frac{1}{n}}$就比较小了,所以我们可以直接枚举一定数量的$n$,然后取最小值。
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 long long L; 5 double getAns(long long x) { 6 return x*pow(L,1.0/x); 7 } 8 int main() { 9 freopen("princess.in","r",stdin); 10 freopen("princess.out","w",stdout); 11 scanf("%lld",&L); 12 long long l=1,r=1e18,mid; 13 while(r-l>2) { 14 long long ll=l+(r-l)/3,rr=r-(r-l)/3; 15 if(getAns(ll)<=getAns(rr)) r=rr; 16 else l=ll; 17 } 18 double ans=L; 19 while(l<=r) { 20 ans=std::min(ans,getAns(l++)); 21 } 22 printf("%.10f\n",ans); 23 return 0; 24 }
J - Orcish Transportation
网络流。这个题,由于图是对称的,故我们可以猜想,相互对应的两条边的流量是可以进行平均的,所以,我们直接跑最大流然后输出两条边的平均值。但是,这题流量为浮点数,且输出要求比较谜,它说需要尽可能的精确,注意到输入描述中说明了流量最多为包含四位小数,故我们可以化成整数,也就是都乘以$10^4$,最后答案再除以$10^4$即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 typedef long long ll; 6 const int maxm=3e5+5; 7 int n,m,f; 8 const ll INF=1e17; 9 bool vis[maxm]; 10 struct node { 11 int to,nxt; ll cap; 12 }edge[maxm];int ecnt=0; 13 int q[maxm],l=0,r=0;// 数组模拟队列 14 int head[605],level[605],iter[605]; 15 void init() { 16 for(int i=1;i<=2*n;i++) head[i]=-1; 17 ecnt=0; 18 } 19 void add(int from, int to, ll cap) { 20 int &i=ecnt; 21 edge[i].to=to;edge[i].cap=cap;edge[i].nxt=head[from];head[from]=i++; 22 edge[i].to=from;edge[i].cap=0;edge[i].nxt=head[to];head[to]=i++; 23 } 24 void bfs(int s) { 25 for(int i=1;i<=2*n;i++) level[i]=-1; 26 level[s]=0; 27 l=r=0; 28 q[r++]=s; 29 int x; 30 while(l<r) { 31 x=q[l++]; 32 for(int i=head[x];i!=-1;i=edge[i].nxt) { 33 node& e=edge[i]; 34 if(e.cap>0&&level[e.to]<0) { 35 level[e.to]=level[x]+1; 36 q[r++]=e.to; 37 } 38 } 39 } 40 } 41 ll dfs(int v, int t, ll f) { 42 if(v==t) return f; 43 for(int &i=iter[v];i!=-1;i=edge[i].nxt) { 44 node& e=edge[i]; 45 if(e.cap>0&&level[v]<level[e.to]) { 46 ll d=dfs(e.to,t,min(f,e.cap)); 47 if(d>0) { 48 e.cap-=d; 49 edge[i^1].cap+=d; 50 return d; 51 } 52 } 53 } 54 return 0; 55 } 56 ll maxFlow(int s,int t) { 57 ll flow=0; 58 while(true) { 59 bfs(s); 60 if(level[t]<0) return flow; 61 for(int i=1;i<=2*n;i++) iter[i]=head[i]; 62 ll f; 63 while((f=dfs(s,t,INF))>0) 64 flow+=f; 65 } 66 } 67 ll W[maxm]; 68 int match[605]; 69 int main(){ 70 freopen("transportation.in","r",stdin); 71 freopen("transportation.out","w",stdout); 72 scanf("%d%d",&n,&m); int u, v; double w; 73 init(); 74 for(int i=1;i<=n;i++) match[i]=i+n, match[i+n]=i; 75 char s[30]; 76 for(int i=1;i<=m;i++){ 77 scanf("%d%d%s",&u,&v,s); ll t=0; 78 int len=strlen(s),p=-1; 79 for(int i=0;i<len;i++) { 80 if(s[i]=='.') p=i; 81 else t=t*10+s[i]-'0'; 82 } 83 if(p==-1) t*=10000; 84 else { 85 p=4-(len-p-1); 86 while(p--) t=t*10; 87 } 88 vis[ecnt]=1; W[ecnt]=t; add(u,v,t), add(match[v],match[u],t); 89 } 90 double ans=maxFlow(1,n+1); 91 printf("%.10f\n",ans*1.0/10000); 92 for(int i=0;i<ecnt;i++){ 93 if(!vis[i]) continue; 94 double t=2*W[i]-edge[i].cap-edge[i+2].cap; 95 printf("%.10f\n",t*1.0/2/10000); 96 } 97 return 0; 98 }