不知道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;}}}
}