问题 E:
暴力DP
根据题意可推出四种状态:
1.当上一个音符和当前音符都为-1时,可得到dp[i][a[i]]=dp[i-1][a[i-1]]+score[a[i-1]][a[i]];
2.当上一个音符为-1,当前音符不为-1时,可得到dp[i][a[i]]=max(dp[i][a[i]],dp[i-1][j]+score[j][a[i]]);
3.当上一个音符不为-1,当前音符为-1时,可得到dp[i][j]=max(dp[i][j],dp[i-1][a[i-1]]+score[a[i-1]][j]);
4.当上一个音符和当前音符都不为-1时,可得到dp[i][k]=max(dp[i][k],dp[i-1][j]+score[j][k]);
只需枚举每次的状态即可。
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<algorithm> 6 #include<queue> 7 #include<vector> 8 #include<stack> 9 #include<map> 10 #include<set> 11 #include<cmath> 12 #include<cctype> 13 #include<ctime> 14 #define INF 0x3f3f3f3f 15 #define PI acos(-1.0) 16 #define MOD 998244353 17 typedef long long ll; 18 typedef unsigned long long ull; 19 20 using namespace std; 21 22 int dp[1005][1005]; 23 int score[1005][1005]; 24 int a[1005]; 25 26 int main() 27 { 28 // freopen("test1.in","r",stdin); 29 // freopen("test1.out","w+",stdout); 30 int t; 31 scanf("%d",&t); 32 while(t--) 33 { 34 memset(dp,0,sizeof(dp)); 35 int n,m,maxn=0; 36 scanf("%d%d",&n,&m); 37 for(int i=1;i<=m;i++) 38 for(int j=1;j<=m;j++) 39 scanf("%d",&score[i][j]); 40 for(int i=1;i<=n;i++) 41 scanf("%d",&a[i]); 42 for(int i=2;i<=n;i++) 43 { 44 if(a[i-1]>0&&a[i]>0) 45 dp[i][a[i]]=dp[i-1][a[i-1]]+score[a[i-1]][a[i]]; 46 else if(a[i-1]>0&&a[i]<0) 47 { 48 for(int j=1;j<=m;j++) 49 dp[i][j]=max(dp[i][j],dp[i-1][a[i-1]]+score[a[i-1]][j]); 50 } 51 else if(a[i-1]<0&&a[i]<0) 52 { 53 for(int j=1;j<=m;j++) 54 for(int k=1;k<=m;k++) 55 dp[i][k]=max(dp[i][k],dp[i-1][j]+score[j][k]); 56 } 57 else 58 { 59 for(int j=1;j<=m;j++) 60 dp[i][a[i]]=max(dp[i][a[i]],dp[i-1][j]+score[j][a[i]]); 61 } 62 } 63 for(int i=1;i<=n;i++) 64 maxn=max(maxn,dp[n][i]); 65 printf("%d\n",maxn); 66 } 67 // fclose(stdin); 68 // fclose(stdout); 69 return 0; 70 }
问题 H:
F = A*X^2 + B*X + C 由于A,B,C(1<=A<=10000,1<=B<=10000,1<=C<=10000) 可得X>=-B/(2*A)时,F(X)一定是单调递增的
所以对于同一部番来说,第I级的动漫肯定比第I+1级动漫花费的钱少。所以对于每部番我们只需要维护我们还没有看的集数最小
的那一集就可以了,使用优先队列维护,算法流程如下:
1.将N部番的第一集放入优先队列
2.从优先队列中取花费最小的一集并弹出队列,假设该集为第I部番的第J集,花费为F(I,J)
3.将F(I,J)加至答案,将第I部番的第J+1集加入优先队列
4.如果已经加了M集,则结束,否则跳转至步骤2
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long Lint; 4 const int max_n = 3*1e5+1e2; 5 const Lint mod = 998244353; 6 7 struct Node{ 8 Lint a,b,c; 9 int dep; 10 Lint val; 11 friend bool operator <(const Node &n1,const Node &n2){ 12 return n1.val>n2.val; 13 } 14 }; 15 16 int n,m; 17 priority_queue<Node> que; 18 19 void solve(){ 20 Node node; 21 scanf("%d %d",&n,&m); 22 for(int i=0;i<n;i++){ 23 scanf("%lld %lld %lld",&node.a,&node.b,&node.c); 24 node.val=node.a+node.b+node.c; 25 node.dep=1; 26 que.push(node); 27 } 28 Lint res=0; 29 while(m--){ 30 res+=que.top().val; 31 node=que.top(); 32 que.pop(); 33 node.dep++; 34 node.val=node.a*node.dep*node.dep+node.b*node.dep+node.c; 35 que.push(node); 36 } 37 printf("%lld\n",res); 38 } 39 40 int main(){ 41 solve(); 42 return 0; 43 }
问题 G:
从根节点开始遍历,对于遍历到的节点统计它的子节点中叶子节点数量X,答案增加(X+1)/2向下取整,对于它的非叶子子节点,则加入遍历序列,继续遍历。
需要注意的是,由于节点有2000000个,所以并不能使用递归遍历(递归深度过深会爆栈,详情请了解堆内存和栈内存),故而我这里是使用BFS进行遍历。
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 int d[2123456],v[2123456]; 4 vector<int> maps[2123456]; 5 queue<int> team; 6 int main(){ 7 int n; 8 scanf("%d",&n); 9 memset(d,0,sizeof(d)); 10 memset(v,0,sizeof(v)); 11 for(int i=1;i<n;i++){ 12 int l,r; 13 scanf("%d%d",&l,&r); 14 maps[l].push_back(r);maps[r].push_back(l); 15 d[l]+=1;d[r]+=1; 16 } 17 team.push(1); 18 int ans = 0; 19 while(!team.empty()){ 20 int x = team.front();team.pop(); 21 v[x] = 1; 22 int p,gs = 1; 23 for(int i=0;i<maps[x].size();i++){ 24 p = maps[x][i]; 25 if(v[p]) continue; 26 if(d[p]==1) gs+=1; 27 else{ 28 team.push(p); 29 } 30 } 31 ans = ans + (gs/2); 32 } 33 printf("%d",ans); 34 return 0; 35 }
问题 K:
这道题是个模拟题目,每一步怎么做题目中都有说。
我们可以重载运算符来方便地进行文科理科,不同科目不同要求的排序。
对于第一次专业分配,我们可以对每一个专业维护进入它的最低分数,来判断是否存在有人所有分数相同但是名额不够的情况。
对于第二次专业分配使用优先队列,map或者set维护当前的最优专业进行分配即可,需要注意没有专业可以分配的情况。
也就是代码量、细心和debug能力的考验,在一堆考验智商的题目中算是良心题目了。
1 #include<iostream> 2 #include<cstdlib> 3 #include<ctime> 4 #include<cstring> 5 #include<string> 6 #include<cstdio> 7 #include<map> 8 #include<vector> 9 #include<algorithm> 10 using namespace std; 11 struct Data { 12 int a[6]; 13 int number; 14 int sum; 15 void read() { 16 sum = 0; 17 for (int i = 0; i<5; i++) { 18 cin >> a[i]; 19 sum += a[i]; 20 } 21 } 22 bool operator<(const Data&pt)const { 23 if (sum != pt.sum) return sum>pt.sum; 24 if (a[3] != 0) {//wenke 25 if (a[0] != pt.a[0]) return a[0]>pt.a[0]; 26 if (a[2] != pt.a[2]) return a[2]>pt.a[2]; 27 if (a[1] != pt.a[1]) return a[1]>pt.a[1]; 28 if(a[3] !=pt.a[3]) return a[3]>pt.a[3]; 29 return number<pt.number; 30 } 31 else { 32 if (a[1] != pt.a[1]) return a[1]>pt.a[1]; 33 if (a[2] != pt.a[2]) return a[2]>pt.a[2]; 34 if (a[0] != pt.a[0]) return a[0]>pt.a[0]; 35 if(a[4] !=pt.a[4]) return a[4]>pt.a[4]; 36 return number<pt.number; 37 } 38 } 39 bool operator==(const Data&pt)const { 40 if (a[0] != pt.a[0]) return a[0] == pt.a[0]; 41 if (a[2] != pt.a[2]) return a[2] == pt.a[2]; 42 if (a[1] != pt.a[1]) return a[1] == pt.a[1]; 43 if (a[3] != pt.a[3]) return a[3] == pt.a[3]; 44 return a[4] == pt.a[4]; 45 } 46 }; 47 struct zyData { 48 string zy[6]; 49 int fc; 50 void read() { 51 for (int i = 0; i<5; i++) cin >> zy[i]; 52 cin >> fc; 53 } 54 }; 55 struct xzyData { 56 int num; 57 Data pre; 58 }; 59 struct xzyData2 { 60 int num; 61 string name; 62 bool operator<(const xzyData2 &pt)const { 63 if (num != pt.num) 64 return num > pt.num; 65 else 66 return name < pt.name; 67 } 68 }; 69 vector<Data> wk, lk; 70 vector<Data> wk2, lk2; 71 vector<zyData> stu_zy; 72 map<string, xzyData> maps; 73 map<xzyData2,int> mapswk,mapslk; 74 void read(int x) { 75 Data pt; 76 pt.read(); 77 if (pt.a[3] == 0 && pt.a[4] == 0) { 78 while (true) cout << "ERROR文理相同" << endl; 79 } 80 pt.number = x; 81 if (pt.a[3] == 0) lk.push_back(pt); 82 else wk.push_back(pt); 83 } 84 string xzyname; 85 xzyData pts; 86 string ans[110000]; 87 int main() { 88 // freopen("3.in","r",stdin); 89 // freopen("3.out","w+",stdout); 90 int n, m; 91 scanf("%d", &n); 92 for (int i = 0; i<n; i++) read(i); 93 for (int i = 0; i<n; i++) { 94 zyData pt; pt.read(); stu_zy.push_back(pt); 95 } 96 scanf("%d", &m); 97 for (int i = 0; i<m; i++) { 98 int number; 99 cin >> xzyname >> number; 100 pts.num = number; 101 for (int j = 0; j<5; j++) { 102 pts.pre.a[j] = 0x3f3f3f3f; 103 } 104 maps[xzyname] = pts; 105 } 106 sort(wk.begin(), wk.end()); 107 sort(lk.begin(), lk.end()); 108 for (int i = 0; i<wk.size(); i++) { 109 int number = wk[i].number; 110 int ok = 0;//是否分配成功 111 for (int j = 0; j < 5; j++) { 112 if (wk[i].a[3] != 0 && stu_zy[number].zy[j][0] >= 'a'&&stu_zy[number].zy[j][0] <= 'z') 113 continue; 114 if (wk[i].a[4] != 0 && stu_zy[number].zy[j][0] >= 'A'&&stu_zy[number].zy[j][0] <= 'Z') 115 continue; 116 if (maps.find(stu_zy[number].zy[j]) == maps.end()) 117 continue; 118 if (maps[stu_zy[number].zy[j]].num <= 0) { 119 if (maps[stu_zy[number].zy[j]].pre == wk[i]); 120 else 121 continue; 122 } 123 ok = 1; 124 ans[number] = stu_zy[number].zy[j]; 125 maps[stu_zy[number].zy[j]].pre = wk[i]; 126 maps[stu_zy[number].zy[j]].num = maps[stu_zy[number].zy[j]].num - 1; 127 break; 128 } 129 if (ok) continue; 130 if (stu_zy[number].fc == 0) { 131 ans[number] = "0"; 132 continue; 133 } 134 wk2.push_back(wk[i]); 135 } 136 for (int i = 0; i<lk.size(); i++) { 137 int number = lk[i].number; 138 int ok = 0;//是否分配成功 139 for (int j = 0; j < 5; j++) { 140 if (lk[i].a[3] != 0 && stu_zy[number].zy[j][0] >= 'a'&&stu_zy[number].zy[j][0] <= 'z') 141 continue; 142 if (lk[i].a[4] != 0 && stu_zy[number].zy[j][0] >= 'A'&&stu_zy[number].zy[j][0] <= 'Z') 143 continue; 144 if (maps.find(stu_zy[number].zy[j]) == maps.end()) 145 continue; 146 if (maps[stu_zy[number].zy[j]].num <= 0) { 147 if (maps[stu_zy[number].zy[j]].pre == lk[i]); 148 else 149 continue; 150 } 151 ok = 1; 152 maps[stu_zy[number].zy[j]].pre = lk[i]; 153 ans[number] = stu_zy[number].zy[j]; 154 maps[stu_zy[number].zy[j]].num = maps[stu_zy[number].zy[j]].num - 1; 155 break; 156 } 157 if (ok) continue; 158 if (stu_zy[number].fc == 0) { 159 ans[number] = "0"; 160 continue; 161 } 162 lk2.push_back(lk[i]); 163 } 164 map<string, xzyData>::iterator ptsp; 165 for (ptsp = maps.begin(); ptsp != maps.end(); ++ptsp) { 166 if (ptsp->second.num <= 0) 167 continue; 168 xzyData2 np; 169 np.name = ptsp->first; 170 np.num = ptsp->second.num; 171 if (ptsp->first[0]>='A'&&ptsp->first[0]<='Z') 172 mapswk[np] = 1; 173 else 174 mapslk[np] = 1; 175 } 176 for (int i = 0; i < wk2.size(); i++) { 177 if (mapswk.empty()|| mapswk.begin()->first.num<=0) { 178 ans[wk2[i].number] = "0"; continue; 179 } 180 ans[wk2[i].number] = mapswk.begin()->first.name; 181 xzyData2 np; 182 np.name = mapswk.begin()->first.name; 183 np.num = mapswk.begin()->first.num - 1; 184 mapswk.erase(mapswk.begin()); 185 if (np.num <= 0) { 186 continue; 187 } 188 else { 189 mapswk[np] = 1; 190 } 191 } 192 for (int i = 0; i < lk2.size(); i++) { 193 if (mapslk.empty() || mapslk.begin()->first.num <= 0) { 194 ans[lk2[i].number] = "0"; continue; 195 } 196 ans[lk2[i].number] = mapslk.begin()->first.name; 197 xzyData2 np; 198 np.name = mapslk.begin()->first.name; 199 np.num = mapslk.begin()->first.num - 1; 200 mapslk.erase(mapslk.begin()); 201 if (np.num <= 0) { 202 continue; 203 } 204 else { 205 mapslk[np] = 1; 206 } 207 } 208 /* 209 for(int i=0;i<wk.size();i++) 210 cout<<wk[i].sum<<endl; 211 for(int i=0;i<lk.size();i++) 212 cout<<lk[i].sum<<endl;*/ 213 for (int i = 0; i < n; ++i) 214 cout << ans[i] << endl; 215 // fclose(stdin); 216 // fclose(stdout); 217 return 0; 218 }
问题 C:
题意,n个排在一条线上的球 围绕其中心旋转,现移动k个球,使其每个球到新中心的距离的平方的和最小。
思路,将k个球移动至剩余(n-k)个球的新中心,则这k个球到新中心距离的平方都为0则,一定会是最小值。所以实际上并不是移动k个球而是删除k个球,使得剩余(n-k)个球到新中心距离平方和最小。题中提示新中心其实就是平均值。那么其实就是在求n个球删除k个球,剩余n-k个球的方差。
解法:I=Σ(1~n)[(ai-center)*(ai-center)]拆开得到:I=Σai*ai-2*d*Σai+nd*d (这里的I即所求,n代指n-k,d表示新中心的位置) 再把d=[Σ(1~n)[ai]]/n带入即可化简。
化简过程如图
公式可得只需在排序后求得前缀和与前缀平方和即可。
代码:
1 #include<bits/stdc++.h> 2 3 #define ms(a,x) memset(a,x,sizeof(a)) 4 using namespace std; 5 6 #define N 50005 7 #define MAX 100002 8 9 typedef long long ll; 10 const int maxt=1e4+5; 11 const int maxn=1e4+5; 12 const int mod=998244353; 13 14 ll a[N]; 15 ll x[N],y[N]; 16 17 int main(){ 18 int t; 19 cin>>t; 20 21 22 while(t--){ 23 int n,k; 24 cin>>n>>k;ll minn=99999999999999999999; 25 for(int i=1;i<=n;i++) 26 cin>>a[i]; 27 if(n==k||n==k+1){ 28 printf("0\n");continue; 29 } 30 sort(a+1,a+n+1); 31 ms(x,0);ms(y,0); 32 for(int i=1;i<=n;i++){ 33 x[i]=x[i-1]+a[i]; 34 y[i]=y[i-1]+a[i]*a[i]; 35 } 36 for(int i=1;i<=k+1;i++){ 37 ll aa=y[i+n-k-1]-y[i-1]; 38 ll bb=x[i+n-k-1]-x[i-1]; 39 aa*=(n-k)*1ll; 40 ll cc=aa-bb*bb; 41 minn=min(minn,cc); 42 } 43 printf("%.3f\n",(double)minn/(double)(n-k)); 44 } 45 return 0; 46 }