题目大意:v1和v2在玩游戏,玩家得到一个整数n,在轮到她的时候,可以对整数进行加1或者减1的操作,如果v1操作后,整数能够整除3,那么她就胜利了,如果10次移动后,v1还没有胜利,那么v2就胜利了。最后v1胜利就打印"First",否则打印"Second".
思路:能整除3即模3得0,一个数模上3只有三种情况,0,1,2;如果因为v1必须要操作,所以,实际上只要这个数n%3!=0,那么v1就会胜利,否则v2只需要复原v1的操作就能使v1每次都得对3的倍数操作,进而无法得到能整除3的数。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n;
scanf("%d",&n);
if(n%3) printf("First\n");
else printf("Second\n");
}
}
题目大意:有排成一排的n个货物,可以选择每辆车装多少个,要求每辆车装的数量一样多,同时每辆车总和的最大值和最小值的差值最大。装箱顺序为,若选择每车装x个,那么1-x装在第一辆车,x+1-2x装在第二辆车……以此类推,求出最大差值。
思路:这道题,连续一段装在一辆车,且要求和,很容易想到前缀和,那么该如何选择一车装多少个呢?实际上暴力就可,不用担心会超时,那么嵌套循环的第二层不一定会跑。
#include<bits/stdc++.h>
using namespace std;
#define int long long
int a[150010],sum[150010];
signed main()
{
int t;
scanf("%lld",&t);
while(t--)
{
int n;
scanf("%lld",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
for(int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i];
int ans=0;
for(int i=1;i<=n-1;i++)
{
if(n%i==0)
{
int mx=0,mi=150000000000000;
for(int j=i;j<=n;j+=i)
//1-i在一车
{
int d=sum[j]-sum[j-i];
mx=max(mx,d);
mi=min(mi,d);
}
ans =max(ans,mx-mi);
}
}
printf("%lld\n",ans);
}
}
题目大意:给定一个数组,要求出其非空子数组和的最大值,同时还要求非空子数组中的元素必须是奇偶相间。
思路:这个就是连续子序列求最大和的变式。累加,当遇到奇偶性不符合,或者加完得到负数的时候,重置即可。另外零对总和无贡献,但是会卡奇偶性,所以如果需要以0开头,那么尽量后跳一下,同样负数也是,所以尽量不以0和负数开头。
#include<bits/stdc++.h>
using namespace std;
#define int long long
int a[200010];
signed main()
{
int t;
scanf("%lld",&t);
while(t--)
{
int n;
scanf("%lld",&n);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
int k=1,mx=-1e9-7;;
//全部小于等于0
while(a[k]<=0&&k<=n) mx=max(mx,a[k]),k++;
if(k>n) printf("%lld\n",mx);
else if(k==n) printf("%lld\n",a[n]);
else
{
int sum=a[k],c=a[k],mx=a[k];//!!!a[k]后面可能全是小于它的数
for(int i=k+1;i<=n;i++)
{
if(c==-1e9-7)
{
sum=a[i];
mx=max(sum,mx);
c=a[i];
continue;
}
if((c%2==0&&a[i]%2)||(c%2&&a[i]%2==0))
{
sum += a[i];
if(sum<0)
{
k=i;
while(a[k]<=0&&k<=n) k++;
i=k-1;
sum=0;
c=-1e9-7;
}
c=a[i];
mx=max(mx,sum);
}
else
{
k=i;
while(a[k]<=0&&k<=n) k++;
i=k-1;
c=-1e9-7;
sum=0;
}
}
printf("%lld\n",mx);
}
}
}
题目大意:给定一个数组,数组里面的每个数ai表示的实际是2^ai,我们定义(a,b)是满足(2^a)^(2^b)=(2^b)^(2^a),问数组中有多少对ai,aj,满足i<j,(ai,aj).
思路:
所以,只有i,j,相等,或者一个为1,一个为2时才能满足。而题目给的i<j的意义不过是限制每一对不能重复计算,即换位置后不重复记录。那么我们只需要统计出每一种的数量,然后处理一下即可。k=mp[i],那么i产生的就是(k-1)*k/2, 1,2产生的就是mp[1]*mp[2].
#include<bits/stdc++.h>
using namespace std;
#define int long long
map<int,int>mp;
signed main()
{
int t;
scanf("%lld",&t);
while(t--)
{
int n;
scanf("%lld",&n);
for(int i=1;i<=n;i++)
{
int x;
scanf("%lld",&x);
mp[x]++;
}
int ans=0;
for(auto it:mp)
{
int ti=it.second;
ans += (ti-1)*ti/2;
}
ans += mp[1]*mp[2];
cout<<ans<<endl;
mp.clear();
}
}
题目大意:给定一个数组,我们可以进行若干次操作,每次操作将第一个数取出,放到末尾,然后去跟前面的比,如果前面的数大于它,那么就进行交换。问最少进行多少次操作可以是数组变成非递减的,如果不能使数组变成非递减的,那么就输出-1。
思路:这个题有点像冒泡排序,我们可以得到的结论就是,第一个数被取出放到后面,一定会放到一个对它来说有序的位置,或者换句话说,被操作过的数都会被放在有序的位置上,那么我们就要考虑,什么时候不能再进行操作了,很明显是最小的那个数为第一个数的时候,因为它还会被放回来,所以它后面的数也不能被操作。如果后面的数就是非递减的,那么自然无所谓,但是如果有递减存在,后面的数是无法被操作的,那么就无法使整个序列有序。所以我们只需要找到最小的数,去看它后面的数是否有递减存在即可。
#include<bits/stdc++.h>
using namespace std;
int a[200010];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n;
scanf("%d",&n);
int idx,mi=1e9+7;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
if(a[i]<mi) mi=a[i],idx=i;
}
int c=a[idx],flag=1;
for(int i=idx+1;i<=n;i++)
{
if(c>a[i])
{
flag=0;
break;
}
c=a[i];
}
if(flag) printf("%d\n",idx-1);
else printf("-1\n");
}
}
题目大意:现有一棵树,要求是第i天,树中要有两叶子节点的距离为di,我们可以进行的操作如下:
选择u,v1,v2,u和v1有边相连,u和v2没有边相连,我们可以将u与v2连起来,同时将u和v1之间的边断掉。现在要我们自己给出一棵树,并给出关于每个di需要如何操作,打印u,v1,v2,如果不需要操作那么就打印-1,-1,-1。只要每步操作合法即可。
思路:这道题看上去非常麻烦,既要我们自己给出一棵树,对每个di,我们还要来找是否已经有合法的点,如果没有该如何操作。但是实际上,有个特别简单的思路,即将n个节点顺次接起来,以1为根节点,我们现在相当于得到了支路1。每次的距离为d,即这条路上有有d+1个点。我们以根节点1作为一个固定的叶子节点,我们来讨论普遍的三种情况:
1.支路1上的点的数量恰好等于d+1,那么就不用进行任何操作,因为从1到叶子节点刚好可以满足要求。
2.支路1上点的数量多于d+1,我们可以将末尾多的点截下来接到支路2后面。(支路2最初为空,表示支路2的数组最初只有节点2,因为1要做叶子节点,所以不能接在1后面)
3.支路1上点的数量小于d+1,那么就将差的那部分从支路2的末尾截下来接到支路1的末尾。
这样就可以满足题目的要求了。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,m;
scanf("%d%d",&n,&m);
vector<int>b1,b2;
for(int i=1;i<=n;i++) b1.push_back(i);
b2.push_back(2);
for(int i=1;i<n;i++) printf("%d %d\n",i,i+1);
while(m--)
{
int d;//距离d
scanf("%d",&d);
d++;
if(d==b1.size())
{
printf("-1 -1 -1\n");
}
else if(d<b1.size())
{
d = b1.size()-d;
//将b1多的接在b2
int v2=b2.back();
vector<int>q;
int u;
for(int i=0;i<d;i++)
{
u=*b1.rbegin();
q.push_back(*b1.rbegin());
b1.pop_back();
}
int v1=b1.back();
cout<<u<<' '<<v1<<' '<<v2<<endl;
for(int i=q.size()-1;i>=0;i--)
{
b2.push_back(q[i]);
}
}
else
{
d =d-b1.size();
int v2=b1.back();
vector<int>q;
int u;
for(int i=0;i<d;i++)
{
u=*b2.rbegin();
q.push_back(*b2.rbegin());
b2.pop_back();
}
int v1=b2.back();
cout<<u<<' '<<v1<<' '<<v2<<endl;
for(int i=q.size()-1;i>=0;i--)
{
b1.push_back(q[i]);
}
}
}
}
}