AtCoder Beginner Contest 267
A - Saturday
#include<bits/stdc++.h>
using namespace std;
int32_t main() {
string s;
cin >> s;
if( s == "Monday" ) cout << "5\n";
if( s == "Tuesday" ) cout << "4\n";
if( s == "Wednesday" ) cout << "3\n";
if( s == "Thursday" ) cout << "2\n";
if( s == "Friday" ) cout << "1\n";
return 0;
}
B - Split?
要判断局面是不是split
,条件有两列没有被全部击倒,但是他们中间有一列被全部击倒。
#include<bits/stdc++.h>
using namespace std;
int32_t main() {
int t[] = { 1,1,2,2,2,1,1};
int st[] = {3,2,4,1,3,5,0,2,4,6};
string s;
cin >> s;
if( s[0] == '1' )
cout << "No\n" , exit(0);
for( int i = 0 ; i <= 9 ; i ++ )
if( s[i] == '0' ) t[ st[i] ] --;
for( int i = 0 ; i <= 6 ; i ++ ){
if( t[i] == 0 ) continue;
for( int j = i + 1 ; j <= 6 ; j ++ ){
if( t[j] > 0 ) continue;
for( int k = j + 1 ; k <= 6 ; k ++ ){
if( t[k] == 0 ) continue;
cout << "Yes\n" , exit(0);
}
}
}
cout << "No\n";
return 0;
}
C - Index × A
假如当前的区间的是S[l,r]
,那么下一个区间的是S[l+1,r+1]=S[l,r]-pre[r]+pre[l-1]+m*a[r+1]
,这样先求一下前缀和,然后 \(O(n)\)的求出所有答案就好。
#include<bits/stdc++.h>
#define int long long
using namespace std;
int read() {
int x = 0, f = 1, ch = getchar();
while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
if (ch == '-') f = -1, ch = getchar();
while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x * f;
}
const int N = 2e5+5;
int n , m , res , a[N] , b[N] , sum ;
int32_t main() {
n = read() , m = read() , res = LONG_MIN;
for( int i = 1 ; i <= n ; i ++ ) a[i] = read() , b[i] = b[i-1] + a[i];
for( int i = 1 ; i < m ; i ++ )
sum += a[i] * i;
for( int i = m ; i <= n ; i ++ ){
sum += m * a[i];
res = max( res , sum );
sum -= b[i] - b[i-m];
}
cout << res << "\n";
return 0;
}
D - Index × A(Not Continuous ver.)
与上一题不同的原因是这道题B可以是不连续的。
呢这样化就可以 dp 来做这道题,首先f[i][j]
,表示前i
个数中选j
个的最大值,那么则有f[i][j]=max(f[i-1][j-1]+a[i]*m , f[i-1][j])
,然后就是老生常谈的滚动数组加倒序枚举优化一维空间
#include<bits/stdc++.h>
#define int long long
using namespace std;
int read() {
int x = 0, f = 1, ch = getchar();
while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
if (ch == '-') f = -1, ch = getchar();
while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x * f;
}
const int N = 2005;
int n , m , a[N] , f[N];
int32_t main() {
n = read() , m = read() ;
for( int i = 1 ; i <= m ; i ++ ) f[i] = LONG_MIN;
for( int i = 1 ; i <= n ; i ++ ) a[i] = read();
for( int i = 1 ; i <= n ; i ++ )
for( int j = min( m , i ) ; j >= 1 ; j -- )
f[j] = max( f[j] , f[j-1] + a[i] * j );
cout << f[m] << "\n";
return 0;
}
E - Erasing Vertices 2
有一个图,每次可以删掉一个点,删掉一个点的代价是这个点所连的边数,删掉一个点后所有与点相连的边也会被删掉。
优先删掉连边少的点,用优先队列来维护一下就好。这里删掉一个点后还要更新所有与这个点相连的点,更新可以把新的状态直接插入优先队列,然后对于每个点只有第一次出队时计算一下共享。
#include<bits/stdc++.h>
#define int long long
using namespace std;
int read() {
int x = 0, f = 1, ch = getchar();
while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
if (ch == '-') f = -1, ch = getchar();
while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x * f;
}
const int N = 2e5+5;
int n , m , val[N] , cost[N] , res = LONG_MIN;
bitset<N> vis;
vector<int> e[N];
priority_queue< pair<int,int> > q;
int32_t main() {
n = read() , m = read();
for( int i = 1 ; i <= n ; i ++ ) val[i] = read();
for( int u , v ; m ; m -- ){
u = read() , v = read();
e[u].push_back(v) , e[v].push_back(u);
cost[u] += val[v] , cost[v] += val[u];
}
for( int i = 1 ; i <= n ; i ++ ) q.emplace( - cost[i] , i );
while( q.size() ){
auto [ c , id ] = q.top(); q.pop() , c = -c ;
if( vis[id] ) continue;
vis[id] = 1;
res = max( res , c );
for( auto it : e[id] ){
if( vis[it] ) continue;
cost[it] -= val[id];
q.emplace( - cost[it] , it );
}
}
cout << res << "\n";
}