A. Game with Integers
题意
a和b在玩游戏,开局给定一个数n,两人轮流操作,每次操作可以将n加一或减一,a先操作,如果a操作之后n可以被3整除,那么a获胜,如果十回合过去a还没有获胜,那么b获胜。如果a获胜输出first,b获胜输出second
分析
如果n是3的倍数,那么无论a怎么操作,b只需要执行与a相反的操作,让n一直保持不变,那么不可能在a操作之后n变为3的倍数,b获胜。
如果n不是3的倍数,那么其可以表示为3x+1,3x+2,那么a第一次操作一定可以通过减一可以把3x+1变为3的倍数,通过加一把3x+2变为3的倍数。
代码
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
//#include<queue>
//#include<map>
//#include<vector>
//#include<set>
//#include<deque>
//#include<bitset>
//#include<functional>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
typedef pair<int,int>PII;
int main()
{
int t;cin>>t;
while(t--)
{
int n;cin>>n;
if(n%3==0) puts("Second");
else puts("First");
}
return 0;
}
B. 250 Thousand Tons of TNT
题意
有n个箱子排成一排,每个箱子重量为ai,现在可以按顺序将这些箱子装上k辆卡车,要求每辆卡车上的箱子数量相同,求箱子重量差值最大的两辆卡车的箱子重量差值。
分析
因为要求每辆卡车的箱子数量相同,所以k只能是n的因数,我们枚举所有可能的k,取差值最大的答案即可
代码
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
//#include<queue>
//#include<map>
#include<vector>
//#include<set>
//#include<deque>
//#include<bitset>
//#include<functional>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
typedef pair<int,int>PII;
const int N=12e5+10;
ll f[N];
ll s[N];
int main()
{
int t;cin>>t;
while(t--)
{
int n;cin>>n;
vector<ll>a;
for(int i=1;i<=n;i++)
{
cin>>f[i];
s[i]=s[i-1]+f[i];
}
ll ans=-1e18;
for(int i=1;i<=n;i++)
{
if(n%i==0)
{
ll mx=-1e18,mn=1e18;
for(int j=i;j<=n;j+=i)
{
mx=max(mx,s[j]-s[j-i]);
mn=min(mn,s[j]-s[j-i]);
}
ans=max(ans,mx-mn);
}
}
cout<<ans<<endl;
}
return 0;
}
C. Yarik and Array
题意
给定一个n个元素的数组a,求其中元素和最大的非空连续子数组的元素和,而且保证相邻元素的奇偶性不同。
分析
对于最大的非空连续子数组,我们可以发现,如果下一个可以加入的数是正数,那么肯定将其加入子数组中更好;如果下一个数是负数,我们需要看这个负数之后有没有符合条件的更大的正数,负数对答案的贡献取决于其后面是否有更优的正数,例如 1 2 3 -2 999 此时我们选择-2是因为后面有999可以使答案更优;但如果原来的子数组之和加上这个负数之后变成了负数,我们还有必要选择这个负数吗,例如 1 2 3 -10 999 此时若我们选择-10,子数组之和将变成-5+999,很明显不如我们单选999更优,所以当我们加上一个负数导致原子数组之和也变为负数之后,我们不如直接舍弃原来的子数组,从下一个正数继续开始选择。
那么基于以上策略,我们只需要再加入判断连续元素奇偶性是否不同即可
代码
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
//#include<queue>
//#include<map>
//#include<vector>
//#include<set>
//#include<deque>
//#include<bitset>
//#include<functional>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
typedef pair<int,int>PII;
const int N=2e5+10;
int f[N];
int main()
{
int t;cin>>t;
while(t--)
{
int n;cin>>n;
ll sum=0;
int flag=2;//上一个数的奇偶性,添加第一个数时不要求奇偶性
ll ans=-1e9;
for(int i=1;i<=n;i++)
{
cin>>f[i];
if(abs(f[i])%2 != flag)
{
sum+=f[i];
flag=abs(f[i])%2;
ans=max(ans,sum);
if(sum<0)//当前子数组和小于0的话直接舍弃
{
sum=0;
flag=2;
}
}
else
{
sum=f[i];//不满足奇偶性,舍弃之前的子数组,从这个数开始继续新的选择
flag=abs(f[i])%2;
ans=max(ans,sum);
if(sum<0)
{
sum=0;
flag=2;
}
}
}
cout<<ans<<endl;
}
return 0;
}
D. Yarik and Musical Notes
题意
有点阅读理解了,大意就是给定一个数组a,存在一个b数组,其每个元素的含义为2^a[i],求存在几个元素满足b[i]^b[j]==b[j]^b[i],其中i<j。
分析
让a^b==b^a,其中a和b都为2^n,对于这样的指数级增长其实是十分难以满足的,枚举几个数之后可以发现,只有2^4==4^2满足要求,其余符合要求的只能是由两个相同的数构成n^n==n^n
那么对于不是4和2的数,我们每次仅累加这个数后面有多少个与其相同的数,对于2和4,我们不仅累加其后与其相同的数的个数,还需要累加其后4或2的个数,(2累加4的个数,4累加2的个数),映射到a数组之中便是1和2
代码
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
//#include<queue>
#include<map>
//#include<vector>
//#include<set>
//#include<deque>
//#include<bitset>
//#include<functional>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
typedef pair<int,int>PII;
const int N=2e5+10;
map<ll,ll>mp;
int f[N];
int main()
{
int t;cin>>t;
while(t--)
{
int n;cin>>n;
mp.clear();
for(int i=1;i<=n;i++)
{
cin>>f[i];
mp[f[i]]++;
}
ll ans=0;
for(int i=1;i<=n;i++)
{
mp[f[i]]--;
ans=ans+max(mp[f[i]],0ll);
if(f[i]==1) ans+=mp[2];
if(f[i]==2) ans+=mp[1];
}
cout<<ans<<endl;
}
return 0;
}
E. Queue Sort
题意
给定一个n个元素的数组a,每次必须按顺序执行以下两个操作:
1.将第一个元素放置到数组末尾
2.将末尾的元素与其之前的元素不交换,直到其大于前一个元素或成为第一个元素
若可以通过操作将数组变为非递减的,输出操作次数,否则输出-1
分析
很明显每次操作一定可以将第一个元素放回到正确的位置上,但如果第一个元素是数组中最小的元素,那么它还会回到第一个元素的位置,那么对于处在这个元素后面的元素,就无法通过操作改变其位置,所以我们只需要判断最小的那个元素后面的元素是否是非递减的顺序排列,因为最小的元素之前的元素都可以通过操作变为非递减的顺序
代码
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
//#include<queue>
//#include<map>
//#include<vector>
//#include<set>
//#include<deque>
//#include<bitset>
//#include<functional>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
typedef pair<int,int>PII;
const int N=2e5+10;
int f[N];
int s[N];
int main()
{
int t;cin>>t;
while(t--)
{
int n;cin>>n;
for(int i=1;i<=n;i++)
{
cin>>f[i];
s[i]=f[i];
}
sort(s+1,s+n+1);
for(int i=1;i<=n;i++)
{
if(f[i]==s[1])
{
if(is_sorted(f+i+1,f+n+1))
{
cout<<i-1<<endl;
break;
}
else
{
cout<<-1<<endl;
break;
}
}
}
}
return 0;
}
F. Alex's whims
题意
最阅读理解的一集,大意为给定了一棵树和一个数组d,d[i]表示第i天所期望的长度,期望长度的含义为树中存在两个叶子结点的距离,为了树每天都存在这样的叶子结点符合期望长度,我们每天可以进行一次操作,将一个节点从原先所在节点连接到一个新的节点,例如 4 3 2代表将4号结点从3号结点移走,接入到2号结点之后,请你输出树的结构和第i天的操作,如果第i天不需要操作则输出-1 -1 -1
分析
因为只关心叶结点的距离,我们可以发现如果我们将树按照一条链的方式排列,对于每天要求的期望长度,我们只需要更改最后一个结点的位置即可
代码
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
//#include<queue>
//#include<map>
//#include<vector>
//#include<set>
//#include<deque>
//#include<bitset>
//#include<functional>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
typedef pair<int,int>PII;
const int N=510;
int d[N];
int main()
{
int t;cin>>t;
while(t--)
{
int n,m;
cin>>n>>m;
for(int i=1;i<=m;i++) cin>>d[i];
for(int i=1;i<=n-1;i++) cout<<i<<" "<<i+1<<endl;
int length=n-1;//长度
for(int i=1;i<=m;i++)
{
if(d[i]==n-1 && length==n-1)
{
cout<<-1<<" "<<-1<<" "<<-1<<endl;
}
else
{
if(d[i]==n-1)//期望长度为最大链长
{
cout<<n<<" "<<length<<" "<<n-1<<endl;//将n点从原先的点放到n-1点,由于摆放的缘故,原先所在的点就是长度
length=d[i];//更新链长
}
else
{
cout<<n<<" "<<length<<" "<<d[i]<<endl;
length=d[i];
}
}
}
}
return 0;
}