Codeforces Round 986 (Div. 2)題解記錄(A~D)

长皆發表於2024-11-11

不知道cf重新交透過會重新算積分,直接多扣了300積分,真難繃,引以為戒吧
比賽連結:https://codeforces.com/contest/2028

A. Alice's Adventures in "Chess"

愛麗絲正試圖在鄉村與紅皇后會面!目前,愛麗絲位於位置\((0, 0)\),紅皇后位於位置\((a, b)\)。愛麗絲只能朝四個基本方向(北、東、南、西)移動。
更正式地說,如果愛麗絲在點\((x, y)\),她將執行以下操作之一:

  • 向北移動(用N表示),移動到\((x, y+1)\)
  • 向東移動(用E表示),移動到\((x+1, y)\)
  • 向南移動(用S表示),移動到\((x, y-1)\);或者
  • 向西移動(用W表示),移動到\((x-1, y)\)
    愛麗絲的移動是預先確定的。她有一個字串\(s\),代表她從左到右執行的一系列移動。一旦她到達序列的末尾,她將永遠重複相同的移動模式。
    你能幫愛麗絲計算出她是否最終會與紅皇后相遇嗎?

\(Input\)
每個測試包含多個測試用例。第一行包含測試用例的數量\(t\)\(1 \le t \le 500\))。測試用例的描述隨後給出。
每個測試用例的第一行包含三個整數\(n\)\(a\)\(b\)\(1 \le n\)\(a\)\(b \le 10\))——字串的長度和紅皇后的初始座標。
第二行包含一個長度為\(n\)的字串\(s\),只由字元N,E,S或W組成。
\(Output\)
對於每個測試用例,輸出一個字串“YES”或“NO”(不帶引號),表示愛麗絲最終是否會與紅皇后相遇。
\(Sample\)
6
2 2 2
NE
3 2 2
NNE
6 2 1
NNEESW
6 10 10
NNEESW
3 4 2
NEE
4 5 5
NEWS


YES
NO
YES
YES
YES
NO

思路:她將永遠重複相同的移動模式。這句話很重要,愛麗絲在一次迴圈中不一定會遇到紅皇后,顯然最壞每次迴圈後最壞移動0或1,因為資料範圍很小直接重複迴圈1000次(多次)就好,看看是否遇到就好,這裡腦抽,賽後一個多小時又交了一發

#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll                                     long long
#define lowbit(x) (x & -x)
#define endl "\n"//                           互動題記得刪除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
ll ksm(ll x, ll y)
{
ll ans = 1;
while (y)
{
if (y & 1)
{
ans = ans % mod * (x % mod) % mod;
}
x = x % mod * (x % mod) % mod;
y >>= 1;
}
return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
if (y == 0)
return x;
else
return gcd(y, x % y);
}
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
int main()
{
    fio();
    ll t;
    cin>>t;
    while(t--)
    {
        ll n,a,b;
        cin>>n>>a>>b;
        string f;
        cin>>f;
        ll cnt,ans;
        cnt=ans=0;
        ll pd=0;
        ll i=0;
        ll gs=4000;
        while(1)
        {
            if(cnt==a&&ans==b)
            {
                pd=1;
                break;
            }
            gs--;
            if(gs==0)
            break;
            if(f[i]=='N')
            {
                ans++;
            }
            else if(f[i]=='S')
            {
                ans--;
            }
            else if(f[i]=='E')
            {
                cnt++;
            }
            else if(f[i]=='W')
            cnt--;
            i++;
            if(i==n)
            {
                i=0;
            }
        }
        if(pd)
        cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
}

B. Alice's Adventures in Permuting

愛麗絲把“變換”和“排列”這兩個詞搞混了!她有一個由三個整數\(n\)\(b\)\(c\)定義的陣列\(a\):陣列\(a\)的長度為\(n\),由\(a_i = b \cdot (i - 1) + c\)給出,對於\(1 \le i \le n\)。例如,如果\(n=3\)\(b=2\)\(c=1\),那麼\(a=[2 \cdot 0 + 1, 2 \cdot 1 + 1, 2 \cdot 2 + 1] = [1, 3, 5]\)
現在,愛麗絲非常喜歡\([0, \ldots, n-1]\)的排列\(^{\text{∗}}\),並且希望將\(a\)轉換成一個排列。在一次操作中,愛麗絲用\(a\)\(\operatorname{MEX}\)\(^{\text{†}}\)替換\(a\)中的最大元素。如果\(a\)中有多個最大元素,愛麗絲選擇最左邊的一個進行替換。
你能幫愛麗絲計算出她需要進行多少次操作才能使\(a\)首次變成一個排列嗎?如果不可能,你應該報告。
\(^{\text{∗}}\)長度為\(n\)的排列是一個由\(0\)\(n-1\)\(n\)個不同整陣列成的陣列,順序任意。請注意,這與排列的常規定義略有不同。例如,\([1,2,0,4,3]\)是一個排列,但\([0,1,1]\)不是排列(\(1\)在陣列中出現了兩次),\([0,2,3]\)也不是排列(\(n=3\)但陣列中有\(3\))。
\(^{\text{†}}\)一個陣列的\(\operatorname{MEX}\)是不屬於該陣列的最小的非負整數。例如,\([0, 3, 1, 3]\)\(\operatorname{MEX}\)\(2\)\([5]\)\(\operatorname{MEX}\)\(0\)
\(Input\)
每個測試包含多個測試用例。第一行包含測試用例的數量\(t\)\(1 \le t \le 10^5\))。隨後是測試用例的描述。
每個測試用例只有一行,包含三個整數\(n\)\(b\)\(c\)\(1\le n\le 10^{18}\)\(0\le b\)\(c\le 10^{18}\))——陣列的引數。
\(Output\)
對於每個測試用例,如果陣列永遠無法變成一個排列,輸出\(-1\)。否則,輸出使陣列變成排列的最小操作次數。
\(Sample\)
7
10 1 0
1 2 3
100 2 1
3 0 1
3 0 0
1000000000000000000 0 0
1000000000000000000 1000000000000000000 1000000000000000000


0
1
50
2
-1
-1
1000000000000000000

思路:給的序列其實是個以c為初項,以b為公差的等差數列,

1.首先思考下不可能條件吧:如果對於目前最右邊的最大數,每次變換後仍然是他最大就是不可能情況,對於一個公差不為0的等差數列,顯然是不會出現這種情況的

所以思考公差為0的情況,列舉下初項為1,4可發現,如果c+1<n-1一定無解

2.有解次數,如何最小化?

其實只要看在這個序列中多個已經符合n排列的數的種類就行了,

如n=4,b=2,c=0時排列一開始為0 2 4 6,顯然,對於每個不符合的數每次會變成符合的數,而且符合的數他是不用變的(當只有一個時)

所以當b>0時,直接根據公式b*i+c<=n-1,求出i(c>n-1時,這裡會得出i<0),否則i=0,然後如果c<=n-1,則i++,否則i不變,最後和n取個min就得出答案了

#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll                                     long long
#define lowbit(x) (x & -x)
#define endl "\n"//                           互動題記得刪除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
ll ksm(ll x, ll y)
{
ll ans = 1;
while (y)
{
if (y & 1)
{
ans = ans % mod * (x % mod) % mod;
}
x = x % mod * (x % mod) % mod;
y >>= 1;
}
return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
if (y == 0)
return x;
else
return gcd(y, x % y);
}
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
int main()
{
    fio();
    ll t;
    cin>>t;
    while(t--)
    {
        ll n,b,c;
        cin>>n>>b>>c;
        if(b==0&&c+1<n-1)
        {
            cout<<-1<<endl;
            continue;
        }
        else 
        {
            ll gs=0;
            ll x=n-1;
            if(b>0)
            gs=(x-c)/b;
            if(c<=n-1)
            gs++;
            cout<<min(n-gs,(ll)n)<<endl;
        }
    }
}

C. Alice's Adventures in Cutting Cake

愛麗絲在瘋帽子的茶會上!有一個由\(n\)節組成的長蛋糕,每節的美味值分別為\(a_1, a_2, \ldots, a_n\)。茶會上有\(m\)個生物,不包括愛麗絲。
愛麗絲將把蛋糕切成\(m + 1\)塊。形式上,她將蛋糕分成\(m + 1\)個子陣列,每個子陣列由一些相鄰的部分構成。一塊蛋糕的美味度是其各節美味度的總和。之後,她將這\(m + 1\)塊蛋糕分給\(m\)個生物和她自己(她的那塊可以是空的)。然而,每個\(m\)個生物只有在其蛋糕塊的美味度至少為\(v\)時才會感到滿意。
愛麗絲希望確保每個生物都滿意。在這一條件下,她還希望最大化她自己那塊蛋糕的美味度。你能幫愛麗絲找到她那塊蛋糕的最大美味度嗎?如果沒有辦法確保每個生物都滿意,請輸出\(-1\)
\(Input\)
每個測試包含多個測試用例。第一行包含測試用例的數量\(t\)\(1 \le t \le 10^4\))。隨後是測試用例的描述。
每個測試用例的第一行包含三個整數\(n, m, v\)\(1\le m\le n\le 2\cdot 10^5\)\(1\le v\le 10^9\))——蛋糕的節數、生物的數量以及每個生物對美味度的最小要求。
下一行包含\(n\)個空格分隔的整數\(a_1, a_2, \ldots, a_n\)\(1 \le a_i \le 10^9\))——各節蛋糕的美味度。
所有測試用例中\(n\)的總和不超過\(2\cdot 10^5\)
\(Output\)
對於每個測試用例,輸出愛麗絲能夠獲得的最大美味度,或者如果沒有辦法確保每個生物都滿意,則輸出\(-1\)
\(Sample\)
7
6 2 1
1 1 10 1 1 10
6 2 2
1 1 10 1 1 10
6 2 3
1 1 10 1 1 10
6 2 10
1 1 10 1 1 10
6 2 11
1 1 10 1 1 10
6 2 12
1 1 10 1 1 10
6 2 12
1 1 1 1 10 10


22
12
2
2
2
0
-1

思路:我們一開始肯定無法直接知道從什麼點開始到什麼點結束為愛麗絲能拿的最大美味度,所以既然我不知道,那我每個都試試唄

首先用字首和字尾陣列wz1,wz2處理好到某個點能有多少個人被分配好蛋糕,還要用另一個字首陣列pre處理好字首和,隨後將字尾陣列轉成正序陣列,然後每到i就知道已經分好了wz1[i-1]個人,所以還要分m-wz1[i-1]個人,直接二分(lower_bound)那個正序陣列找到第一個符合的下標i1,然後n-i1,(記得二分包含0位置哦),即可得到愛麗絲在符合題意狀況下能拿到的區間蛋糕(pre[n-i1]-pre[i-1]),在所有可能中取個最大值就好

#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll                                     long long
#define lowbit(x) (x & -x)
#define endl "\n"//                           互動題記得刪除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
ll ksm(ll x, ll y)
{
ll ans = 1;
while (y)
{
if (y & 1)
{
ans = ans % mod * (x % mod) % mod;
}
x = x % mod * (x % mod) % mod;
y >>= 1;
}
return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
if (y == 0)
return x;
else
return gcd(y, x % y);
}
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
ll pre[250000];
ll sub[250000];
ll wz1[250000];
ll wz2[250000];
ll a[250000];
ll ok[250000];
int main()
{
    fio();
    ll t;
    cin>>t;
    while(t--)
    {
        ll n,m,v;
        cin>>n>>m>>v;
        for(ll i=1;i<=n;i++)cin>>a[i],sub[i]=0,pre[i]=0,wz1[i]=0,wz2[i]=0;
        sub[n+1]=0;
        ll sum=0;
        for(ll i=1;i<=n;i++)
        {
            sum+=a[i];
            pre[i]=pre[i-1]+a[i];
            wz1[i]=max(wz1[i],wz1[i-1]);
            if(sum>=v)
            {
               sum=0;
               wz1[i]++;
            }
        }
        sum=0;
        wz2[n+1]=0;
        for(ll i=n;i>=1;i--)
        {
            sum+=a[i]; 
            wz2[i]=max(wz2[i],wz2[i+1]);
            if(sum>=v)
            {
                wz2[i]++;
                sum=0;
            }
            ok[n-i+1]=wz2[i];
        }
      //  cout<<wz1[n]<<endl;
        if(wz1[n]<=m-1)
        {
            cout<<-1<<endl;
        }
        else 
        {
            ll ans=0;
            for(ll i=1;i<=n;i++)
            {
                ll x=wz1[i-1];
                ll u=m-x;
                ll op=lower_bound(ok,ok+1+n,u)-ok;
                ans=max(ans,pre[n-op]-pre[i-1]);
            }
            cout<<ans<<endl;
        }
    }
}

D. Alice's Adventures in Cards
愛麗絲正在和紅心皇后、紅心國王以及紅心傑克玩牌。在他們的牌遊戲中有\(n\)種不同型別的牌。愛麗絲目前有一張型別為\(1\)的牌,並且需要一張型別為\(n\)的牌才能逃離仙境。其他玩家每人都有每種型別的一張牌。
在這個牌遊戲中,愛麗絲可以和另外三個玩家交換牌。每個玩家對\(n\)種型別的牌有不同的偏好,這可以透過排列\(q\)\(k\)\(j\)來描述,分別對應皇后、國王和傑克的偏好。
如果對於玩家的排列\(p\)\(p_a > p_b\),那麼這個玩家更看重牌\(a\)而不是牌\(b\)。然後,這個玩家願意用牌\(b\)和愛麗絲交換牌\(a\)。愛麗絲的偏好很直接:如果\(a > b\),她就更看重牌\(a\)而不是牌\(b\),而且她也只會根據這些偏好進行交易。
確定愛麗絲是否可以根據這些偏好,從型別為\(1\)的牌交易到型別為\(n\)的牌,如果可能的話,請給出一組可能的交易方式。
\(^{\text{∗}}\)長度為\(n\)的排列是一個由\(n\)個不同的整陣列成的陣列,這些整數從\(1\)\(n\),順序任意。例如,\([2,3,1,5,4]\)是一個排列,但\([1,2,2]\)不是排列(\(2\)出現了兩次),而且\([1,3,4]\)也不是排列(\(n=3\)但陣列中有\(4\))。
\(Input\)
每個測試包含多個測試用例。第一行包含測試用例的數量\(t\)\(1 \le t \le 10^4\))。
每個測試用例的第一行包含一個整數\(n\)\(2\le n\le 2\cdot 10^5\))——牌的型別數量。
接下來的三行包含皇后、國王和傑克的偏好。這些行每行包含\(n\)個整數\(p_1, p_2, \ldots, p_n\)\(1\le p_i\le n\))——對應玩家偏好的排列。
所有測試用例中\(n\)的總和不超過\(2\cdot 10^5\)
\(Output\)
對於每個測試用例,在第一行輸出一個字串"YES"或"NO"(不包括引號),表示愛麗絲是否可以交易到牌\(n\)
如果第一行是"YES",那麼在下一行輸出\(k\)——愛麗絲將進行的交易次數。在接下來的\(k\)行中,輸出空格分隔的一個字元\(c\in \{\texttt{q}, \texttt{k}, \texttt{j}\}\)和一個整數\(x\),表示愛麗絲與玩家\(c\)交易以獲得牌\(x\)。必須滿足在第\(k\)行,\(x = n\)。如果有多個解決方案,請列印任何一個。
你可以以任何情況(大寫或小寫)輸出這個答案。例如,字串"yEs"、"yes"、"Yes"和"YES"將被視為肯定的回應。同樣,表示交易中玩家的字元\(c\)\(\texttt{Q}, \texttt{K}, \texttt{J}\)將與它們的小寫變體一起被接受)。
\(Sample\)
2
3
1 3 2
2 1 3
1 2 3
4
2 3 1 4
1 2 3 4
1 4 2 3


YES
2
k 2
q 3
NO

思路:由答案可知,我得輸出過程,所以一定是dfs或者bfs,思考下bfs,不好寫,因為過程會有問題(資料儲存量會太大),所以就dfs了,一開始想建邊,但是明顯\(n^2\)的時間複雜度,所以否決,然後想了下題目給了兩個約束,即優先度,和愛麗絲只能換更大的數,顯然如果我dfs,一個數搜過了,之後一定不會搜了,所以準備記憶化+dfs,然後在想的時候最佳化了下遍歷時間,一開始用3個set根據權值(優先度)對於q,k,j的手牌進行排序,隨後開了兩個二維陣列,一個記錄對應數的位置,還有一個記錄排序後的數隨後直接dfs+記憶化(這裡用的是兩個二維陣列)就過了,但是時間是1468ms,有點危險,看了下樣例全是NO才是1468ms,其他都是<900ms就過了,所以如果要最佳化下,看下能否特判不行情況吧,這裡也腦抽重新交了一發,積分--,具體時間複雜度自己也不清楚

#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll                                     long long
#define lowbit(x) (x & -x)
#define endl "\n"//                           互動題記得刪除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
ll ksm(ll x, ll y)
{
ll ans = 1;
while (y)
{
if (y & 1)
{
ans = ans % mod * (x % mod) % mod;
}
x = x % mod * (x % mod) % mod;
y >>= 1;
}
return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
if (y == 0)
return x;
else
return gcd(y, x % y);
}
void fio()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
set<pair<ll,ll>>q[4];
bool vis[250000];
vector<pair<char,ll>>ans;
ll pd=0;
ll n;
ll a[4][250000];
ll b[4][250000];
void dfs(ll x)
{ 
    vis[x]=1;
    if(x==n)
    {
        pd=1;
        return ;
    }
    ll wz;
    wz=a[1][x];
   // ll op=0;
    for(ll i=wz+1;i<=n;i++)
    {
        if(b[1][i]>x&&vis[b[1][i]]==0)
        {
            ans.push_back({'q',b[1][i]});
            dfs(b[1][i]);
            if(pd)
            return ;
            ans.pop_back();
        }
    }
     wz=a[2][x];
     for(ll i=wz+1;i<=n;i++)
    {
        if(b[2][i]>x&&vis[b[2][i]]==0)
        {
            ans.push_back({'k',b[2][i]});
            dfs(b[2][i]);
            if(pd)
            return ;
            ans.pop_back();
        }
    }  
      wz=a[3][x];
     for(ll i=wz+1;i<=n;i++)
    {
        if(b[3][i]>x&&vis[b[3][i]]==0)
        {
            ans.push_back({'j',b[3][i]});
            dfs(b[3][i]);
            if(pd)return ;
            ans.pop_back();
        }
    }
}
int main()
{
    fio();
    ll t;
    cin>>t;
    while(t--)
    {
     pd=0;
     cin>>n;
     ans.clear();
     q[1].clear();
     q[2].clear();
     q[3].clear();
     for(ll i=1;i<=3;i++)
     {
        for(ll j=1;j<=n;j++)
        {
            ll w;
            cin>>w;
            vis[w]=0;
            q[i].insert({n-w+1,j});
        }
        ll cnt=0;
        for(auto j:q[i])
        {
            cnt++;
            a[i][j.second]=cnt;
            b[i][cnt]=j.second;
        }
     }
     dfs(1);
     if(pd==0)
     {
        cout<<"NO"<<endl;
     }
     else 
     {
        cout<<"YES"<<endl;
        cout<<ans.size()<<endl;
        for(auto j:ans)
        {
            cout<<j.first<<" "<<j.second<<endl;
        }
     }
    }
}

E. Alice's Adventures in the Rabbit Hole

思路:賽時沒調出來,但是先給個想法吧,僅供參考,就是以1為根節點,然後回溯時進行失敗機率和計算,最後輸出時,用mod-失敗機率即可

相關文章