2020CSP-J普及组复赛
https://ac.nowcoder.com/acm/contest/8848#question
A-优秀的拆分(power)
解法一:
任意一个自然数都可以拆分成若干个不同的2的幂次方的和,比如1100010100,相当于1不断向左移,而1向左移动一位就相当于乘2,题目说是正整次幂,所有二进制第一位不能为一,否则会加一,不和题意。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <stack>
#include <queue>
#include <string.h>
#include <cmath>
#include <bitset>
#include <set>
#include <map>
#include <list>
#define ll long long
const int inf = 0x3f3f3f3f;
const int mod = 1e4+7;
const ll ds = 1e15+7;
const double p = 3.141592653589793238462643383;
using namespace std;
int main()
{
int n,res = 1;
int a[55],t = 0;
cin >> n;
if(n & 1) cout << "-1";
else{
while(n){
if(n&1) a[t++] = res;
res <<= 1;
n >>= 1;
}
for(int i = t-1; i >= 0; i--){
cout << a[i] << " ";
}
}
return 0;
} 解法二:先找出1-1e7中2幂次数有哪些,然后从后往前取 #include <iostream>
#include <cstdio>
#include <algorithm>
#include <stack>
#include <queue>
#include <string.h>
#include <cmath>
#include <bitset>
#include <set>
#include <map>
#include <list>
#define ll long long
const int inf = 0x3f3f3f3f;
const int mod = 1e4+7;
const ll ds = 1e15+7;
const double p = 3.141592653589793238462643383;
using namespace std;
int cnt = 0;
int a[55],n,vis[55],b[5500];
void init()
{
ll res = 2;
a[cnt++] = 2;
while(res <= 1e7){
res *= 2;
a[cnt++] = res;
}
}
int main()
{
init();
cin >> n;
if(n & 1) cout << "-1";
else{
int t = 0;
for(int i = cnt-1; i >= 0; i--){
if(n >= a[i]) {
b[t++] = a[i];
n -= a[i];
}
}
for(int i = 0; i < t; i++){
cout << b[i] << " ";
}
}
return 0;
} 解法三:DFS搜索,因为只有24个数,DFS+剪枝可以满足 #include <iostream>
#include <cstdio>
#include <algorithm>
#include <stack>
#include <queue>
#include <string.h>
#include <cmath>
#include <bitset>
#include <set>
#include <map>
#include <list>
#define ll long long
const int inf = 0x3f3f3f3f;
const int mod = 1e4+7;
const ll ds = 1e15+7;
const double p = 3.141592653589793238462643383;
using namespace std;
int cnt = 0;
int a[55],n,vis[55];
void init()
{
ll res = 2;
a[cnt++] = 2;
while(res <= 1e7){
res *= 2;
a[cnt++] = res;
}
}
int flag = 0;
int b[55];
void dfs(int res,int xb)
{
//cout << res << endl;
if((res <= 1 && res != 0) || flag == 1){
return;
}
if(res == 0){
flag = 1;
int t = 0;
for(int i = 0; i < cnt; i++){
if(vis[i]) b[t++] = a[i];
// cout << i << " ";
}
sort(b,b+t);
for(int i = t-1; i >= 0; i--){
cout << b[i] << " ";
}
return;
}
for(int i = 0; i < xb; i++){//因为先去了xb之后的数,接下来要取的数只能是1-xb-1 之间的数,这一步缺少会超时。
if(vis[i] || res < a[i]) continue;
vis[i] = 1;
dfs(res-a[i],i);
vis[i] = 0;
}
}
int main()
{
init();
cin >> n;
dfs(n,cnt-1);
if(!flag) cout << "-1" << endl;
return 0;
} B-直播获奖
思路:大根堆+小根堆,一般两者是在一起使用的。大根堆在左,小根堆在右,用小根堆的大小去维护获奖人数,每次输出小根堆的堆顶元素。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <stack>
#include <queue>
#include <string.h>
#include <cmath>
#include <bitset>
#include <set>
#include <map>
#include <list>
#define ll long long
const int inf = 0x3f3f3f3f;
const int mod = 1e9;
const ll ds = 1e15+7;
const double p = 3.141592653589793238462643383;
using namespace std;
priority_queue<int,vector<int>,less<int> >q1;//大根堆
priority_queue<int,vector<int>, greater<int> >q2;//小根堆
int b[1000005];
int main()
{
int num = 0,n,w,x;
scanf("%d%d",&n,&w);
for(int i = 1; i <= n; i++){
scanf("%d",&x);
int hj_num = i*w/100;
hj_num = max(1,hj_num);
if((!q2.empty() && q2.top() <= x) || q2.empty()){
q2.push(x);
}
else q1.push(x);
while(q2.size() < hj_num){
int temp = q1.top();
q1.pop();
q2.push(temp);
}
while(q2.size() > hj_num){
int temp = q2.top();
q2.pop();
q1.push(temp);
}
printf("%d ",q2.top());
}
return 0;
}
D-放格取数:动态规划
dfs超时代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <stack>
#include <queue>
#include <string.h>
#include <cmath>
#include <bitset>
#include <set>
#include <map>
#include <list>
#define ll long long
const int inf = 0x3f3f3f3f;
const int mod = 1e4+7;
const ll ds = 1e15+7;
const double p = 3.141592653589793238462643383;
using namespace std;
struct node{
int x,y;
node(int a,int b){
x = a;
y = b;
}
};
int dir[3][2] = {{-1,0},{1,0},{0,1}};
int vis[10005][10005];
ll a[10005][10005] = {0},ans = -ds;
int n,m;
bool check(int x,int y)
{
if(x <= 0 || x > n || y <= 0 || y > m) return false;
return true;
}
void dfs(int x,int y,ll l)
{
//cout << l <<endl;
// cout << x << y << endl;
if(x == n && y == m){
ans = max(l,ans);
// cout << ans << endl;
return;
}
for(int i = 0; i < 3; i++){
int dx = x + dir[i][0];
int dy = y + dir[i][1];
// cout << dx << dy << endl;
if(vis[dx][dy]) continue;
if(check(dx,dy)){
vis[dx][dy] = 1;
dfs(dx,dy,1ll*(l+a[dx][dy]));
vis[dx][dy] = 0;
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
scanf("%lld",&a[i][j]);
}
}
vis[1][1] = 1;
dfs(1,1,a[1][1]);
printf("%lld\n",ans);
return 0;
}
动态规划:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <stack>
#include <queue>
#include <string.h>
#include <cmath>
#include <bitset>
#include <set>
#include <map>
#include <list>
#define ll long long
const int inf = 0x3f3f3f3f;
const int mod = 1e9;
const ll ds = 1e15+7;
const double p = 3.141592653589793238462643383;
using namespace std;
int n,m;
ll dp[1005][1005][2],a[1005][1005];
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
scanf("%lld",&a[i][j]);
}
}
memset(dp, -0x3f, sizeof dp);
dp[1][0][0] = 0;
for(int j = 1; j <= m; j++){
for(int i = 1; i <= n; i++){
dp[i][j][0] = max(dp[i-1][j][0],max(dp[i][j-1][1],dp[i][j-1][0])) + a[i][j];
}
for(int i = n; i >= 1; i--){
dp[i][j][1] = max(dp[i+1][j][1],max(dp[i][j-1][0],dp[i][j-1][1])) + a[i][j];
}
}
printf("%lld",max(dp[n][m][1],dp[n][m][0]));
return 0;
}
