目录
B - Road to Arabella(博弈论)
题意:给一个n和k,每个人每次可以从max(1,n-k)中选一个数,然后把n减去这个数。n为0时游戏结束。把0摆在对方面前就是赢了。
题解:(遇到这种题时考虑一下必胜态,必败态会好思考一点)
如此我们很容易想起奇偶性博弈,总能把偶数摆在对方面前,我们就行了,所以对所有n,k;我们要做的是,能不能总是把偶数摆在对方面前。
当n=k+1或者n=k时,选的那个数只能为1。只要这时的n是偶数,那么每次轮到Ayoub选时n都是奇数,轮到Kilani选时n都是奇数,那么Ayoub是必胜的。
当n>k+1时Kilani永远是必胜态,因为他可以让自己选的时候n为奇数。
#include <bits/stdc++.h>
using namespace std;
#define pi 3.1415926
#define X first
#define Y second
#define Ysanqian ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define endl "\n"
#define int long long
#define ULL unsigned long long
#define pb push_back
typedef pair<int, int> PII;
int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1};
const int N = 3e6 + 100, M = 1010, inf = 0x3f3f3f3f, mod = 1e9 + 7,P=133331;
void solve()
{
int n;
scanf("%d",&n);
while(n--)
{
int a,b;
cin>>a>>b;
if(a==b||a-1==b)
{
if(a&1)printf("Kilani\n");
else printf("Ayoub\n");
}
else printf("Kilani\n");
}
}
signed main()
{
Ysanqian;
int T;
T=1;
//cin >> T;
while (T--)solve();
return 0;
}
D - Meeting Bahosain(gcd)
题意:给定a,b数组,b数组不存在相同元素,进行以下操作,选一个a[i], 让其进行任意次的加减b数组的任意数,问是否可以让a数组全部相等
思路:设一个数x,a[i]-a[j]=x(i,j为任意下标),x=b[1]*x1+b[2]*x2+...+b[n]*xn,
然后好像就是扩展欧几里德了(可能说错了)
( 即如果a、b是整数,那么一定存在整数x、y使得ax+by=gcd(a,b)。
换句话说,如果ax+by=m有解,那么m一定是gcd(a,b)的若干倍)
那么x=k*gcd(b1,b2,b3...bn),那么我们检查每个a[i]-a[j]是否可以整除gcd(b1,b2,b3,b4...bn)就可以了(其实只需枚举相邻的元素即可)
#include <bits/stdc++.h>
using namespace std;
#define pi 3.1415926
#define X first
#define Y second
#define Ysanqian ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define endl "\n"
#define int long long
#define ULL unsigned long long
#define pb push_back
typedef pair<int, int> PII;
int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1};
const int N = 3e6 + 100, M = 1010, inf = 0x3f3f3f3f, mod = 1e9 + 7,P=133331;
int n,m;
bool flag;
int a[N],b[N];
int gcd(int a,int b)
{
return b?gcd(b,a%b):a;
}
void solve()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=m;i++)
cin>>b[i];
int res=b[1];
for(int i=2;i<=n;i++)
res=gcd(res,b[i]);
for(int i=2;i<=n;i++)
{
int dis=a[i]-a[i-1];
if(dis%res!=0)
{
flag=1;
break;
}
}
if(flag)
cout<<"No"<<endl;
else
cout<<"Yes"<<endl;
}
signed main()
{
Ysanqian;
int T;
T=1;
//cin >> T;
while (T--)solve();
return 0;
}
I. Bashar and Hamada
题意:给你一个 数组 a[N]让你选则元素大于2的子数组,使得子数组里面的所有数的差的绝对值最大。
思路:
1.首先n=2时,肯定选择数组中的最大值和最小值,这样F2=max-min
2.n=3时,在F2的基础上,无论选择哪个都是一样的,假设选取的数是x,F3=F2 + max - x + x - min = 2 * F2
3.n=4时,在F3的基础上,随便取一个数 y, F4 =F3 + max - y + y - min +| y - x | = F3 + F2 + | y - x | ,要想使F4最大,x、y需要分别为剩下数中最小值和最大值。
所以我们可以相到sort一下,最小最大依次选取,一定是最优的
具体可以看一下这个
首先我们应该明白顺序是不影响大小的。然后再找一个规律:
假定一组数据 {1,2,3,4,5,7},开始ans=0;
2:开始:ans+= |1-7|
3:插入5: ans+=|5-1|+|5-7|=|1-7|
4:插入2: ans+=|2-1|+|2-7|+|2-5|==|1-7|+|2-5|
5:插入4: ans+=|4-1|+|4-7|+|4-5|+|4-2|==|1-7|+|2-5|
6:插入3: ans+=|3-1|+|3-7|+|3-5|+|3-2|+|3-4|==|1-7|+|2-5|+|3-4|
这样列出来就很明显了ans位递推的
偶数个加上当前未选过的max-min
奇数个则加上当前有那些max-min对
每次组合都选差最大的,排序后,就是左右各一个。
思路转载自这个博客:
原文链接:https://blog.csdn.net/qq_62802647/article/details/125626195
#include <bits/stdc++.h>
using namespace std;
#define pi 3.1415926
#define X first
#define Y second
#define Ysanqian ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define endl "\n"
#define int long long
#define ULL unsigned long long
#define pb push_back
typedef pair<int, int> PII;
int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1};
const int N = 3e6 + 100, M = 1010, inf = 0x3f3f3f3f, mod = 1e9 + 7,P=133331;
int n,a[N];
void solve()
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
sort(a+1,a+1+n);
int ans=0,sum=0;
int l=1,r=n;
for(int k=2;k<=n;k++)
{
if((k&1)==0)sum+=(a[r--]-a[l++]);
ans+=sum;
cout<<ans<<' ';
}
}
signed main()
{
Ysanqian;
int T;
T=1;
//cin >> T;
while (T--)solve();
return 0;
}
J - Thanos Power
题意:就是给你一个很大的数,让你从初始0经过两个操作分别得到这个数
两个操作为
1:增加一个10的x次方
2:减少一个10的x次方(x对应的其为第几位,例如1020中1对应的x为3)
其实就是让某一位加一或减一
这题当时没有看,后来补的
思路:对于每一位上的数i有两种的得到的方式:1:直接从0加到i,所需操作数为i .2:上一位加1,然后从此位上减,所需操作数为1+10-i,
f[i][j]:(j取0或1,0表示通过2操作,1表示通过1操作)
状态表示:dp[i][j]代表第0到第i位上的数采用j种方式所需的最小操(注意这里得上一位是前一个高位,我们从最大位开始循环)
状态计算:
1:如果这一维是从0上升得到的数字,我们这一位操作数就为s[i]-'0',我们要对上一位得操作取min所以f [ i ] [ 1 ] = min ( f [ i − 1 ] [ 0 ] , f [ i − 1 ] [ 1 ] ) + s[i]-'0' 即可 ;
2:如果这一维是从高位下降得来的数,那么如果前一维也是下降的话,可以让前一维少下降一位,很明显这样做可以使得当前为得到这个数的步数更小。同理,如果前一位是从低位升上来的,这一维需要从高位降,那没有办法,只能让前一维多走一步(即前一位加一),再加上当前位数从高位降下来的值。d p [ i ] [ 0 ] = min ( d p [ i − 1 ] [ 0 ] − 1 , d p [ i − 1 ] [ 1 ] + 1 ) + 10 − (s[ i ]- ' 0 ');
#include <bits/stdc++.h>
using namespace std;
#define pi 3.1415926
#define X first
#define Y second
#define Ysanqian ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define endl "\n"
#define int long long
#define ULL unsigned long long
#define pb push_back
typedef pair<int, int> PII;
int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1};
const int N = 3e6 + 100, M = 1010, inf = 0x3f3f3f3f, mod = 1e9 + 7,P=133331;
int f[N][2];
string s;
void solve()
{
cin>>s;
int n=s.size();
f[0][0]=11-(s[0]-'0');
f[0][1]=s[0]-'0';
for(int i=1;i<n;i++)
{
f[i][1]=min(f[i-1][0],f[i-1][1])+s[i]-'0';
f[i][0]=min(f[i-1][0]-1,f[i-1][1]+1)+10-(s[i]-'0');
}
cout<<min(f[n-1][0],f[n-1][1])<<endl;
}
signed main()
{
Ysanqian;
int T;
T=1;
//cin >> T;
while (T--)solve();
return 0;
}
M. Two Operations
题意:给你一个字符串和两个操作,求进位之后的字典序最大的答案。
1:交换任意两个字符的位置
2:你可以删除具有相同值的任意两个相邻字符,并按字母顺序将它们替换为下一个字符
例如aa可以变成b,但是zz不能在变了
这题你一开始想的用栈来写,毕竟变完之后还有可能和后面的依然相等这样也能过,但是太麻烦了
然后发现了另一种方法
思路:用个数组记录每个字母出现的次数,然后从低位开始进位,最后从高位到低位输出即可。
这样像就太简单了。。。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int vis[N];
int main(){
string s;
cin>>s;
int len=s.size();
for(int i=0;i<len;i++){
vis[s[i]-'a']++;//这里就变成记录0~25了(一共26个)我有的时候容易想错(蒻)
}
for(int i=0;i<25;i++){
vis[i+1]+=vis[i]/2;
vis[i]%=2;
}
for(int i=25;i>=0;i--){
while(vis[i]--){
cout<<char(i+'a');
}
}
cout<<endl;
return 0;
}