比赛地址:https://codeforces.com/contest/1942
传送门
A. Farmer John’s Challenge
很显然,将最后一位数放到第一位数还能使数组保持有序当且仅当所有数相等。所以要么 k = 1 或 n,要么无解
void solve()
{
int n,k;
cin>>n>>k;
if(n==k) {
while(n--) cout<<1<<' ';
} else if(k==1) {
for(int i=1;i<=n;i++) cout<<i<<' ';
} else {
cout<<-1;
}
cout<<'\n';
}
B. Bessie and MEX
由于保证有解,根据题目意思模拟即可
void solve()
{
int n;
cin>>n;
vector<int> v(n);
vector<int> st(n+1);
for(auto &i: v) cin>>i;
int last=0;
for(auto p: v) {
if(last-p>=0&&!st[last-p]) {
// cout<<'a';
cout<<last-p<<' ';
st[last-p]=true;
} else {
// cout<<'b';
cout<<last<<' ';
st[last]=true;
while(st[last]) last++;
}
}
cout<<'\n';
}
C1. Bessie’s Birthday Cake (Easy Version)
对点排序,将他选的x个点相邻两个两两相连一定是最优解,(因为对于一个x个点的多边形,能够构成的三角形的最大个数为 x - 2,那么点越多三角形就越多)。再看他选的每两个点之间是否夹着一个点,每有一个答案++(因为这两个点连成的边与蛋糕的边缘也能构成一个三角形)
void solve()
{
int n,x,y;
cin>>n>>x>>y;
vector<int> v(x);
for(auto &i: v) cin>>i;
sort(v.begin(),v.end());
ll ans=x-2;
for(int i=1;i<x;i++) {
if(v[i]-v[i-1]==2) ans++;
}
if((v[x-1]+2)%n==v[0]) ans++;
cout<<ans<<'\n';
}
C2. Bessie’s Birthday Cake (Hard Version)
C1的复杂版,主角可以额外选 y 个点。在多边形中的两个已选择的点中间间隔了一个点,显然这个点选不选对答案没有影响,称之无效,在两个已选择的点中间间隔了x(x>1)个点,每间隔一个点选一个点,这样的点可以使答案++,称之有效。在此基础之上,选择奇数个点的区间比偶数个点的区间(当剩余可选择点数量足够时)最后构成三角形的数量更多,所以优先考虑奇数点区间。
别忘了最后一个点和第一个点之间的区间。
void solve()
{
int n,x,y;
cin>>n>>x>>y;
vector<int> v(x);
for(auto &i: v) cin>>i;
ll ans=x-2;
sort(v.begin(),v.end());
vector<int> _diff;
for(int i=1;i<x;i++) {
if(v[i]-v[i-1]>2)
_diff.push_back(v[i]-v[i-1]-1);
else if(v[i]-v[i-1]==2) {
ans++;
}
}
if(v[0]+n-v[x-1]>2) {
_diff.push_back(v[0]+n-v[x-1]-1);
} else if(v[0]+n-v[x-1]==2) {
ans++;
}
sort(_diff.begin(),_diff.end(),[&](int x,int y){return x%2&&y%2?x<y:x%2;});
for(auto diff: _diff) {
// cout<<diff<<' ';
if(diff%2) {
if(diff/2<=y) {
y-=diff/2;
ans+=(diff/2)*2+1;
} else {
ans+=y*2;
y=0;
}
} else {
if(diff/2<=y) {
y-=diff/2;
ans+=(diff/2)*2;
} else {
ans+=y*2;
y=0;
}
}
}
// cout<<'\n';
cout<<ans<<'\n';
}
D. Learning to Paint
不知道是什么dp
维护dp[i][k] 数组表示考虑前 i 个格子的第 k 大数,对于枚举的第 i 个点,有下面三种情况:
- 不选第 i 个数,即 dp[i-1][0]
- 选择第 i 个数,需要考虑包含第 i 个数组的区间的左边界,假设左边界为 j+2,即dp[j][0] + v[j+2][i]
- 选择从1开始到i区间的所有格子,即 v[1][i]
需要将大的数优先放进dp[i] 中,所以使用优先队列,对于每个区间,枚举更新第 k + 1大的结果放入优先队列中。
void solve()
{
int n,k;
cin>>n>>k;
vector v(n+1,vector<int>(n+1));
for(int i=1;i<=n;i++) {
for(int j=i;j<=n;j++) {
cin>>v[i][j];
}
}
vector dp(n+1,vector<int>());
dp[0].push_back(0);
for(int i=1;i<=n;i++) {
priority_queue<array<int,3>> pq;
pq.push({dp[i-1][0],i-1,0});
pq.push({v[1][i],-1,0});
for(int j=i-2;j>=0;j--) {
pq.push({dp[j][0]+v[j+2][i],j,0});
}
while(!pq.empty()&&dp[i].size()<k) {
auto [val,j,num]=pq.top();
pq.pop();
dp[i].push_back(val);
if(j<0||num+1==dp[j].size()) continue;
if(j==i-1) {
pq.push({dp[j][num+1],j,num+1});
} else {
pq.push({dp[j][num+1]+v[j+2][i],j,num+1});
}
}
}
for(auto temp: dp[n]) {
cout<<temp<<' ';
}
cout<<'\n';
}