这可能是我做
以来做的最好的一次?它居然
了!哼╭(╯^╰)╮不给力的服务器!关键时刻拓机!虽然这次的D比较水。但是是我一次过了四题QAQ…
比赛传送门:https://codeforces.com/contest/1106
A. Lunar New Year and Cross Counting
题解:数交叉 个数, 枚举中点即可。
代码
#include<bits/stdc++.h>
using namespace std;
string s[505];
int n;
int count1(int x,int y)
{
if(s[x][y] != 'X') return 0;
int dir[4][2] = {-1,-1,-1,1,1,-1,1,1};
for(int i = 0; i < 4; ++i) {
int tx = x + dir[i][0];
int ty = y + dir[i][1];
if(tx < 0 || tx >= n || ty < 0 || ty >= n)
return 0;
if(s[tx][ty] != 'X') return 0;
}
return 1;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.in","r",stdin);
#endif
cin >> n;
for(int i = 0; i < n; ++i) {
cin >> s[i];
}
int ans = 0;
for(int i = 0; i < n; ++i) {
for(int j = 0; j < n; ++j) {
ans += count1(i,j);
}
}
cout << ans << endl;
return 0;
}
B. Lunar New Year and Food Ordering
题解:按题意模拟,用一个优先队列维护当前最便宜并且 最小的食物,如果当前顾客所需要的食物数量不够,那就取 出来最便宜的食物,直到满足当前顾客,如果满足不了那就输出 ;如果足够当前顾客需要的,那就直接输出数量乘以花费即可。( 千万要注意会爆long long!!)
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1E5+10;
struct node{
int t,d;
}cust[N];
struct food{
int c,d,id;
bool operator < (const food & u) const {
if(d == u.d) {
return id > u.id;
}
return d > u.d;
}
};
priority_queue<food> pq;
int c[N],d[N];
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.in","r",stdin);
#endif
int n,m;
cin >> n >> m;
for(int i = 0; i < n; ++i) {
scanf("%d",&c[i]);
}
for(int i = 0; i < n; ++i) {
scanf("%d",&d[i]);
}
for(int i = 0; i < n; ++i) {
pq.push(food{c[i],d[i],i});
}
for(int i = 0; i < m; ++i) {
scanf("%d%d",&cust[i].t,&cust[i].d);
cust[i].t--;
}
long long tmp = 0;
for(int i = 0; i < m; ++i) {
tmp = 0;
int t = cust[i].t;
int num = cust[i].d;
if(num > c[t]) {
tmp += 1LL * d[t] * c[t];
num -= c[t];
c[t] = 0;
if(pq.empty()) tmp = -1;
while(!pq.empty()) {
if(tmp == -1) break;
food cur = pq.top(); pq.pop();
cur.c = min(cur.c,c[cur.id]);
if(cur.c >= num) {
tmp += 1LL * cur.d * num;
cur.c -= num;
c[cur.id] -= num;
if(cur.c != 0)
pq.push(cur);
break;
}else{
tmp += 1LL * cur.c * cur.d;
num -= cur.c;
c[cur.id] = 0;
}
if(pq.empty()) tmp = -1;
}
}else{
c[t] -= num;
tmp += 1LL * d[t] * num;
}
if(tmp == -1) tmp = 0;
cout << tmp << endl;
}
return 0;
}
C. Lunar New Year and Number Division
说实话这题当时纯靠莽…,题意是给偶数个数,然后分组,每组至少两个,最后求最小化 , 为第 组的数字的和,一共有 组。既然要最小化和,那么就要最小化 ,我当时就猜测,肯定每组两个数,让每组最小的话肯定是最小和最大配,第二小和第二大配。然后莽了一发就A了。
题解:我们可以考虑两个数,
,答案只能是
四个数,
分一组
分两组
对比
显然每组的数量越少,总和越小。我们再观察
,拆开:
如果我们想要
尽可能的小,那么我们就需要最小化
和
,由乘法的性质可得让
和
尽可能大即可。因此我们可以证明最小的和最大的配,第二小和第二大的配,以此类推的做法是正确的。
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 3E5+10;
long long a[N];
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.in","r",stdin);
#endif
int n;
cin >> n;
for(int i = 0; i < n; ++i) {
scanf("%lld",&a[i]);
}
sort(a,a+n);
long long sum = 0;
for(int i = 0; i < n / 2; ++i) {
sum += (a[i] + a[n - i - 1]) * (a[i] + a[n - i - 1]);
}
cout << sum << endl;
return 0;
}
D. Lunar New Year and a Wander
题解:既然要访问的路径字典序最小,那么我们用优先队列+bfs就可以很好解决了。
代码
#include<bits/stdc++.h>
#define P pair<int,int>
using namespace std;
const int N = 1E5+10;
//vector<int> e[N];
priority_queue<int,vector<int>,greater<int> > e[N];
bool vis[N];
vector<int> ans;
priority_queue<int,vector<int>,greater<int> > pq;
void bfs()
{
pq.push(1);
vis[1] = 1;
ans.push_back(1);
while(!pq.empty()) {
int cur = pq.top();
if(vis[cur] == 0) {
vis[cur] = 1;
ans.push_back(cur);
}
pq.pop();
for(; !e[cur].empty(); e[cur].pop()) {
int v = e[cur].top();
pq.push(v);
}
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.in","r",stdin);
#endif
int n,m,x,y;
cin >> n >> m;
for(int i = 0; i < m; ++i) {
scanf("%d%d",&x,&y);
e[x].push(y);
e[y].push(x);
}
bfs();
int len = ans.size();
for(int i = 0; i < len; ++i) {
printf("%d%c",ans[i],i==len-1?'\n':' ');
}
return 0;
}
E. Lunar New Year and Red Envelopes
题意: 在每个 时间段内抢红包,只要在当前时间 可以抢红包,那么他就一定会去抢。然后没抢完一个红包,那么他必须等到 时间才能抢下一个红包。期间 最多可以 次阻挠 在时间 时抢红包。问 最少可以获得多少红包。
题解:我们可以将问题分为两个部分,没有
阻挠,
所能获得的最少收益。和有
不超过
次时间点阻挠最少所能获得的收益。
那么第一部分是可以通过优先队列预处理出来的,同时我们记录每个时间点的收益,和下一次抢红包的时间点。然后对于不超过
次的阻挠,我们可以用动态规划来解决。
表示在
时间时
次阻挠最少所能获得的收益。我们发现状态的转移有
和
两种,并且每次抢完红包必须等到
才能抢,也就意味着下一次抢红包时间是大于你的决策时的时间的,因此我们不妨考虑倒过来转移。(实际上正着来也是可以的,而且官方题解是用的滚动数组)就有
最后答案就是
。
代码
#include<bits/stdc++.h>
typedef long long LL;d
using namespace std;
const int N = 1E5+10;
struct node{
int s,t,d,w;
bool operator < (const node & u) const{
if(w == u.w) return d < u.d;
return w < u.w;
}
};
bool cmp(const node & a, const node & b){ return a.s < b.s; }
priority_queue<node> pq;
vector<node> v;
LL dp[N][201], got[N], nxt[N];
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.in","r",stdin);
#endif
int n,m,k,s,t,d,w;
cin >> n >> m >> k;
for(int i = 0; i < k; ++i) {
cin >> s >> t >> d >> w;
v.push_back(node{s,t,d,w});
}
sort(v.begin(),v.end(),cmp);
int cur = 0;
//1 4
//6 4 + 7
//11 4 + 7 + 9 <!> 11 <!>12 --> 4 + 7 = 11
for(int i = 1; i <= n; ++i) {
while(cur < k && v[cur].s <= i)
pq.push(v[cur++]);
while(!pq.empty() && pq.top().t < i) pq.pop();
if(!pq.empty()){
node t = pq.top();
got[i] = t.w;
nxt[i] = t.d + 1;
}else{
got[i] = 0;
nxt[i] = i + 1;
}
}
memset(dp,0x3f,sizeof dp);
dp[n + 1][0] = 0;
for(int i = n; i > 0; --i) {
dp[i][0] = dp[nxt[i]][0] + got[i];
}
for(int i = n; i >= 1; --i) {
for(int j = 0; j <= m; ++j) {
dp[i][j] = min(dp[i][j], dp[nxt[i]][j] + got[i]);
dp[i][j] = min(dp[i][j], dp[i + 1][j - 1]);
}
}
LL ans = *min_element(dp[1],dp[2]);
cout << ans << endl;
return 0;
}