AtCoder Beginner Contest 277

《D - Takahashi's Solitaire》

思维,看题,循环

 

 

 注意到Ai<M,这个意味着 最大的数 与 最小的数 之间可能会有循环,即一个排好的数(从小到大):

a1,a2,a3,.................,an-1,an; 可能(an+1)%m==a1;

(这道题的难点是强迫自己能1s跑出来)

经过推导我们不难发现:

一旦第一张牌确定了,那么结果也就出来了,我们将排序,去重后第i张牌第一次放的最终结果设为Si

将全部牌求和为all,排序,去重,记录第i张牌的数vi在原来数组中的出现次数为fi;

排序,去重后的数组大小为k

则有:

if (vi+1)%m != v[(i+1)%k]------->S[i]=all-vi*fi

if (vi+1)%m==v[(i+1)%k]--------->S[i]=S[i+1]-vi*fi;

有点dp递推的味道了,要选好一个方向来:即找到第一个(vi+1)%m != v[(i+1)%k]的牌p

即有0~p-1都是(vi+1)%m==v[(i+1)%k]

S[p]=all-vp*fp,S[0~p-1]=S[xxx]-vxxx*fxxx;

然后对于第k-1张牌来说,其上一张牌为0(因为那个%m),很自然我们会想到从k-1,k-2......p+1开始求

 

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <map>
using namespace std;
typedef long long ll;
const int N = 2 * 1e5 + 5;
map<ll, ll> mapp;
vector<ll> arr;
int main()
{
    ll n, m;
    ll all = 0;
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
    {
        int num;
        scanf("%d", &num);
        arr.push_back(num);
        mapp[num]++;
        all += num;
    }
    sort(arr.begin(), arr.end());
    arr.erase(unique(arr.begin(), arr.end()), arr.end());

    int k = arr.size();
    // 找到最小的不连续的
    int p;
    for (int i = 0; i < k; i++)
    {
        if ((arr[i] + 1) % m != arr[(i + 1) % k])
        {
            p = i;
            break;
        }
    }

    ll ans = 1e16, s[N];
    if (p == k - 1)
        ans = 0;
    else
    {
        // 极度要注意一下这里的乘法:会爆int,如果这里不转一下long long 或者 数据不是long long 的则会计算错误
        s[p] = all - arr[p] * mapp[arr[p]];
        for (int i = p - 1; i >= 0; i--)
            s[i] = s[i + 1] - arr[i] * mapp[arr[i]];
        for (int i = k - 1; i >= p + 1; i--)
        {
            if ((arr[i] + 1) % m == arr[(i + 1) % k])
                s[i] = s[(i + 1) % k] - arr[i] * mapp[arr[i]];
            else
                s[i] = all - arr[i] * mapp[arr[i]];
        }
        for (int i = 0; i <= k - 1; i++)
            ans = min(ans, s[i]);
    }
    cout << ans;
    return 0;
}

《E - Crystal Switches》

分层图,图论,双端队列BFS

 

 

 对于这道题:

可以看成每个点都是有两个状态;

 正如样例:在最开始的情况下点1是不能直接到点3的,但是我们到点3处经过反转,点1就可以直接到点3了

 

我们可以将 Hit Switch 操作看成一次不需要代价的状态转移,如图:

这个时候如果我们将图建成上面的样子,那么就可以直接用Dijkstra算法解决,但是在仔细思考一下,因为边的权重只有0与1,则也可以用双端BFS

那么问题来了:如何表示这同一个点,但是是不同状态下的?

可以对于点i,i+n表示其反状态

双端队列BFS的写法十分有讲解,不太熟悉尽量写Dijkstra

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstring>
 4 #include <vector>
 5 #include <deque>
 6 using namespace std;
 7 const int N = 4 * 1e5 + 5;
 8 typedef pair<int, int> PII;
 9 vector<PII> sides[N];
10 int n, m, k;
11 int dist[N];
12 bool vis[N];
13 void BFS()
14 {
15     memset(dist, 0x3f, sizeof(dist));
16     deque<int> dq;
17     dq.push_back(1);
18     dist[1] = 0;
19     while (dq.size())
20     {
21         int v = dq.front();
22         dq.pop_front();
23         // 避免TLE;
24         if (vis[v])
25             continue;
26         // 只有真正从队头出来的才是真正的到点v最短
27         vis[v] = true;
28         for (int i = 0; i < sides[v].size(); i++)
29         {
30             int to = sides[v][i].first, w = sides[v][i].second;
31             if (!vis[to] && dist[v] + w < dist[to])
32             {
33                 dist[to] = dist[v] + w;
34                 if (w == 0)
35                     dq.push_front(to);
36                 else
37                     dq.push_back(to);
38             }
39         }
40     }
41 }
42 int main()
43 {
44     cin >> n >> m >> k;
45     for (int i = 1; i <= m; i++)
46     {
47         int a, b, s;
48         scanf("%d%d%d", &a, &b, &s);
49         if (s == 0)
50             sides[a + n].push_back({b + n, 1}), sides[b + n].push_back({a + n, 1});
51         else
52             sides[a].push_back({b, 1}), sides[b].push_back({a, 1});
53     }
54     for (int i = 1; i <= k; i++)
55     {
56         int v;
57         scanf("%d", &v);
58         sides[v].push_back({v + n, 0}), sides[v + n].push_back({v, 0});
59     }
60     BFS();
61     int ans = min(dist[n], dist[2 * n]);
62     if (ans == 0x3f3f3f3f)
63         ans = -1;
64     cout << ans;
65     return 0;
66 }

 

F - Sorting a Matrix 》

思维,拓扑图

这个我看题解说道了偏序关系建图,这个我实在不会

但是这道题目的核心观点我大概理解了:

 

 

 我们可以明确一个重点:

 

 

 

 

posted @ 2022-11-17 11:05  次林梦叶  阅读(118)  评论(0)    收藏  举报