SDU暑期集训排位(5)题解

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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code

猜你喜欢

转载自www.cnblogs.com/Onlymyheart/p/11312404.html