又还是只能做到 C,太菜了
看看能不能有时间练练 D
A. The Good Array
题意
给定整数 n,k。
构造一个 0−1 序列 a1,a2,…,an,满足:
- 前 i 个元素中至少有 ⌈ki⌉ 个 1。
- 后 i 个元素中至少有 ⌈ki⌉ 个 1。
解法
正解是 O(1) 的(请查看官方题解)。
当时随便写了一个贪心,把 i 从小往大枚举,如果不够就尽量往中间放 1。
我觉得这个贪心很对,但是我不会证,反正确实是对的。
AC 代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| #include<bits/stdc++.h> using namespace std;
#define ll long long #define mem0(x) memset(x,0,sizeof(x))
int read(){ int f=1,x=0; char c; c=getchar(); while(!isdigit(c)){ if(c=='-')f=-1; c=getchar(); } while(isdigit(c)){ x=x*10+c-'0'; c=getchar(); } return x*f; }
const int N = 105; int a[N];
void solve(){ mem0(a); int n=read(),k=read();
for(int i=1;i<=n;i++){ int need = i/k; if(i%k!=0)need++;
int s1 = 0; for(int j=1;j<=i;j++){ s1 += a[j]; } for(int j=i;j>0;j--){ if(s1<need && !a[j]){ a[j]=1; s1++; } }
int s2 = 0; for(int j=n;j>n-i;j--){ s2 += a[j]; } for(int j=n-i+1;j<=n;j++){ if(s2<need && !a[j]){ a[j]=1; s2++; } } }
int ans = 0; for(int i=1;i<=n;i++){ ans += a[i]; } printf("%d\n",ans); }
int main(){ int T=read(); while(T--){ solve(); } return 0; }
|
B. Lamps
题意
有 n 盏灯。每盏灯表示为二元组 (ai,bi)。每盏灯的状态一定是以下三个:打开,关闭,损坏。
你可以打开一盏关闭的灯(没有损坏),获得 bi 分,同时,所有 ai≤当前打开灯数 的灯会立即损坏(无论是否开关)。注意:打开然后已经损坏的灯不计入打开的灯。请问:最多可以获得多少分?
解法
我们先从 a=1 开始考虑。
不难想到,a=1 的灯开完就会坏,然后当前打开灯数变为 0。因此,对于所有 a=1 的灯,一定只能开一盏,贪心开 b 最大的。
我们尝试推广这个结论,推广得到,a=x 的灯能开且最多能开 x 盏。
我们分三种情况证明这个结论:
- a=x 的灯没有:显然成立。
- a=x 的灯大于等于 x 盏:这时候开 x 盏就全部损坏了,结论仍然成立。
- a=x 的灯小于等于 x 盏:这时候不会立即损坏,而是到后面开 a=x+1,a=x+2,… 的时候损坏,而不会影响到后面灯的开关(因为一定在后面灯没有损坏前先全部坏掉了,不占开灯的这个指标了)。
因此,最后只需统计对于每个 a,前 a 大的 b 然后累加即可。
AC 代码
这份代码用了优先队列,不使用优先队列也是完全可以的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| #include<bits/stdc++.h> using namespace std;
#define ll long long
int read(){ int f=1,x=0; char c; c=getchar(); while(!isdigit(c)){ if(c=='-')f=-1; c=getchar(); } while(isdigit(c)){ x=x*10+c-'0'; c=getchar(); } return x*f; }
const int N = 2e5+5;
struct Node{ int a,b; bool operator<(const Node&rhs)const{ return a<rhs.a; } };
void solve(){ int n=read(); vector<Node> v; for(int i=1;i<=n;i++){ int a=read(),b=read(); v.push_back({a,b}); }
sort(v.begin(),v.end());
ll ans = 0; int cur = 0; priority_queue<int> pq; for(int i=1;i<=n;i++){
while(cur<n && v[cur].a == i){ pq.push(v[cur].b);cur++; }
for(int j=1;j<=i;j++){ if(!pq.size())break; ans += pq.top(); pq.pop(); }
while(pq.size())pq.pop(); }
printf("%lld\n",ans); }
int main(){ int T=read(); while(T--){ solve(); } return 0; }
|
C. Insert Zero and Invert Prefix
题意
给定一个 0−1 序列 a1,a2,…,an。
现能对空序列执行 n 次如下操作:往序列中插入一个 0,并反转前面的数。
例:对于序列 101001,往第五个元素后插入一个 0 后,序列变为 0101101 (红色的 0 为插入的 0)
请问:能否确定一个操作,使空序列等于序列 a1,a2,…,an?如果可以,请输出操作。
题解
先考虑最后一个是 1 的情况。这种情况显然是不可能的,因为没有人来反转最后一位。
我们猜想:对于任何最后一位是 0 的序列,都一定存在一个合法的操作,我们尝试构造出这个操作。
观察序列:
1,1,0,1,0,1,1,0
考虑最后的 0 是最后插入的:
0, 0, 1, 0, 1, 0, 0,0
那问题就转化成求解序列:
0,0,1,0,1,0,0
这时候有两个 0,一定先插入最后一个 0,然后构造前面的序列,然后再插入最靠前的 0。
1, 1, 0, 1, 0,0,0
就这样不断递归,直到当前求解的序列全部是 0 即可。
细节参见代码。
AC 代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
| #include<bits/stdc++.h> using namespace std;
#define ll long long #define mem0(x) memset(x,0,sizeof(x))
int read(){ int f=1,x=0; char c; c=getchar(); while(!isdigit(c)){ if(c=='-')f=-1; c=getchar(); } while(isdigit(c)){ x=x*10+c-'0'; c=getchar(); } return x*f; }
const int N = 1e5+5;
int a[N];
void dfs(int x,bool rev){ if(x==1){ printf("0 "); return; } for(int i=x;i>=1;i--){ if(i==1|| a[i]==0 && a[i-1]==1 && !rev || a[i]==1 && a[i-1]==0 && rev){ for(int j=i+1;j<=x;j++){ printf("0 "); }
if(i!=1)dfs(i-1,!rev);
printf("%d ",i-1);
break; } } }
void solve(){ int n=read(); for(int i=1;i<=n;i++){ a[i]=read(); }
if(a[n]==1){ puts("NO");return; }
puts("YES"); dfs(n,0);
puts(""); }
int main(){ int T=read(); while(T--){ solve(); } return 0; }
|