测试地址:牛客竞赛
题意简述
了解炉石传说的应该不难理解题意。太长了还是去看原题面吧/
解题思路
模拟题,需要注意我方随从是从左到右依次进攻的,若忽略这点会浪费很多时间。
Code
队友的代码:
#include
#include
#include
#include
#include
#define ll long long
using namespace std;
const int N = 1007;
int n,cas,a,b,c,d;
char bk[N];
int solve_max(int n, int a, int b, int c, int d){
int res=0;
for (int i=0;i<n;++i){
if (bk[i]=='1'){
if (c){//嘲讽
c--; res++; continue;
}
if (d){//圣盾嘲讽
d--; c++; continue;
}
if (a){//普通
a--; res++; continue;
}
if (b){//圣盾
b--; a++; continue;
}
}else{
if (d){//不是无穷大时先攻击 圣盾嘲讽
d--; c++; continue;
}
if (c){//嘲讽
continue;
}
if (b){//圣盾
b--; a++; continue;
}
}
}
return res;
}
int solve_min(int n, int a, int b, int c, int d){
int res=0;
for (int i=0;i<n;++i){
if (bk[i]=='1'){
if (d){
d--; c++; continue;
}
if (c){
c--; res++; continue;
}
if (b){
b--; a++; continue;
}
if (a){
a--; res++; continue;
}
}else{
if (c) continue;//不是无穷大时先攻击嘲讽
if (d){
d--; c++; continue;
}
if (a) continue;
if (b){
b--; a++; continue;
}
}
}
return res;
}
int main(){
scanf("%d",&cas);
while(cas--){
int cnt = 0;
scanf("%d%d%d%d%d",&n,&a,&b,&c,&d);
scanf("%s",bk);
printf("%d %d\n",solve_max(n,a,b,c,d),solve_min(n,a,b,c,d));
}
return 0;
}
题意简述
解题思路
俺没看这题,队友说是贪心思路。
是先从右向左把f[i]小的先确定 把那些f[i]为-1的 从小到大依次填进去 保证字典序最小。
Code
#include
#include
#include
#include
#include
#define ll long long
using namespace std;
const int N=107;
int n,a[N],ans[N],cas,cnt = 0,cur = 1;
void solve(){
cnt=0,cur=1;
while(cnt<n){
for(int i=n;i;--i)
if(a[i]==cur) ans[i]=++cnt;
for(int i=1;i<=n;++i)
if(a[i]==-1){
a[i]=cur;
ans[i]=++cnt;
break;
}
else if(a[i]==cur) break;
++cur;
}
for(int i=1;i<n;++i) printf("%d ",ans[i]);
printf("%d\n",ans[n]);
}
int main(){
//freopen("data.in","r",stdin);
scanf("%d",&cas);
while(cas--){
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
solve();
}
return 0;
}
题意简述
1~n 共 n 个数,请问怎么排列才能使得所有子区间的平均值 之和最大?
解题思路
易得每个位置上的数被计算的次数是不一样的,容易想象,因为是求平均数之和最大,肯定是越大的数计算次数越多越好,可以举个例子写个小证明。通过打表发现对于一个序列,越靠近中间位置的数被计算的次数越多,所以尽量把大的数放在中间即可。
Code
#include
using namespace std;
const int N = 1e5+10;
int a[N],n;
int main(){
scanf("%d",&n);
int t = 1,p = 1,q = n;
while(t <= n){
a[p++] = t++;
if(t > n) break;
a[q--] = t++;
}
for(int i = 1;i <= n;i++) cout << a[i] << " ";
return 0;
}
Code
#include
#include
#include
#define ll long long
const int N = 107;
int n,m,sx,sy;
char map[N][N];
int ans[N][N];
int bk[N][N];
int dir[][2] = {{-1,2},{1,2},{2,1},{2,-1},{1,-2},{-1,-2},{-2,-1},{-2,1}};
int bar[][2] = {{0,1},{1,0},{0,-1},{-1,0}};
struct Node{
int x,y,step;
}node;
void solve(){
std::queue<Node> que;
node.x = sx,node.y = sy,node.step = 0;
que.push(node);
bk[sx][sy] = 0;
while(que.size()){
Node frt = que.front();
que.pop();
int x = frt.x,y = frt.y,step = frt.step;
//printf("x= %d, y = %d\n",x,y);
for(int i = 0; i < 8; ++i){
int xt = x+dir[i][0],yt = y+dir[i][1];
int xb = x+bar[i/2][0],yb = y+bar[i/2][1];
if(xt < 1 || xt > n || yt < 1|| yt > m) continue;
if(map[xt][yt] != 'X' && map[xb][yb] != 'X' && bk[xt][yt] == -1){
bk[xt][yt] = step+1;
node.x = xt,node.y = yt,node.step = step+1;
que.push(node);
}
}
}
for(int i = 1; i <= n; ++i){
for(int j = 1; j <= m; ++j)
printf("%d ",bk[i][j]);
printf("\n");
}
}
int main(){
//freopen("data.in","r",stdin);
scanf("%d %d",&n,&m);
for(int i = 1; i <= n; ++i){
getchar();
for(int j = 1; j <= m; ++j){
scanf("%c",&map[i][j]);
if(map[i][j] == 'M') sx=i,sy=j;
else bk[i][j] = -1;
}
}
solve();
return 0;
}
题意简述
给定 n 堆石子,第 i 堆有 ai 个石子。合并第 i 堆和第 j 堆的得分是 ai * aj,合并后新堆有 ai+aj 个石子,请问将这 n 个石子合并成一堆的最大得分。
解题思路
这题 n <= 2000,朴素的动态规划需要 O(n^3) ,超时。我猜它可以用四边形不等式优化,结果果然可以,于是没有证明直接套用。
Code
#include
using namespace std;
typedef long long ll;
const int N = 2000+10;
ll f[N][N],a[N],sum[N];
int n,s[N][N];
inline ll w(int i,int k,int j){
return (sum[k]-sum[i-1])*(sum[j]-sum[k]);
}
void solve(){
for(int i = 1;i <= n;i++) sum[i] = sum[i-1] + a[i],s[i][i] = i;
for(int len = 2;len <= n;len++)
for(int i = 1;i <= n-len+1;i++){
int j = i+len-1;
for(int k = s[i][j-1];k < s[i+1][j];k++)
if(f[i][j] < f[i][k]+f[k+1][j]+w(i,k,j)){
f[i][j] = f[i][k]+f[k+1][j]+w(i,k,j);
s[i][j] = k;
}
}
printf("%lld\n",f[1][n]);
}
int main(){
scanf("%d",&n);
for(int i = 1;i <= n;i++) scanf("%lld",a+i);
solve();
return 0;
}