Dashboard - Codeforces Global Round 17 - Codeforceshttps://codeforces.com/contest/1610
目录
A. Anti Light's Cell Guessing
题意:有一个隐藏的格子,我们可以告诉你某个点和它的曼哈顿路径长度(|a1−a2|+|b1−b2|).问最多问几个点可以知道这个隐藏点的位置.
思路:当m==1&&n==1就只有一个点,问0次.当m,n有一个点是0时,那么只需要问一次,其余情况都需要问2次.
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N =5e5+10,mod=998244353;
void solve()
{
int m,n;
cin>>m>>n;
if(m==1&&n==1)
cout<<"0\n";
else if(m==1||n==1)
cout<<"1\n";
else
cout<<"2\n";
}
signed main()
{
int t;
cin>>t;
while(t--)
solve();
return 0;
}
B. Kalindrome Array
Problem - B - Codeforceshttps://codeforces.com/contest/1610/problem/B题意:给你一个数字数组,是否可以删除任意个数的值等于x的数,让数组变成回文数组.
思路:我们只需要从两边往中间分别匹配,当不同时,如果题目给的条件可以成立,那么肯定是删除这两个不同数字中的一个,判断一下就行了.
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N =2e5+10,mod=998244353;
int arr[N],n;
bool check(int x)
{
vector<int>ve;
for(int i=1;i<=n;i++)
{
if(arr[i]!=x)
ve.push_back(arr[i]);
}
vector<int>v1=ve;
reverse(v1.begin(),v1.end());
for(int i=0;i<v1.size();i++)
{
if(v1[i]!=ve[i])
return false;
}
return true;
}
void solve()
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>arr[i];
int f=0;
for(int i=1,j=n;i<=n,j>=0;i++,j--)
{
if(arr[i]!=arr[j])
{
f=1;
if((check(arr[i])|check(arr[j]))==1)
{
cout<<"YES\n";
return ;
}
else
break;
}
}
if(f)
cout<<"NO\n";
else
cout<<"YES\n";
}
signed main()
{
int t;
cin>>t;
while(t--)
solve();
return 0;
}
C. Keshi Is Throwing a Party
Problem - C - Codeforceshttps://codeforces.com/contest/1610/problem/C题意:有n个人,每个人有i元钱(第几个人就有几块钱),每个人拥有属性a,b.即为当满足最多a[i]个人比他富有,最多b[i]个人比他穷,他就是开心的,问最多选几个人满足选的这些人都是开心的.
思路:一眼二分,check函数里面就看在满足条件的情况下我选的人是否大于check的人数即可
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N =2e5+10,mod=998244353;
int n,a[N],b[N];
int check(int x)
{
int cnt=0;
for(int i=1;i<=n;i++)
{
if(b[i]>=cnt&&x-cnt-1<=a[i])
cnt++;
//满足条件,++
}
//cnt为理想状态我选x个人时实际上最多可以选多少人.
if(cnt>=x)
return 1;
else
return 0;
}
void solve()
{
int ans=0;
scanf("%lld",&n);
for(int i=1;i<=n;i++)
scanf("%lld%lld",&a[i],&b[i]);
int l=1,r=n;
while(l<r)
{
int mid=(l+r+1)/2;
if(check(mid))
l=mid;
else
r=mid-1;
}
printf("%lld\n",l);
return ;
}
signed main()
{
int t;
cin>>t;
while(t--)
solve();
return 0;
}
D. Not Quite Lee(裴蜀定理,组合数学)
妙妙题.
Problem - D - Codeforceshttps://codeforces.com/contest/1610/problem/D
题意:给你n个数的数组a.当我们选择a[i]意思为我们可以选择连续的a[i]个数字的数组.比如a[i]=3,就表示我们选择了{x,x+1,x+2}(x可以为任意数字.现在要求我们选任意个数组a中的元素,并且获得他们的数组,让这些数组的元素加起来等于0.问有多少种选法.
思路:
我们对于每个数字生成的子数组进行构造,先放一个0进去,然后按照一个正数,一个负数的顺序放进去(注意数组中每个值都不能相等):{0,1,-1,2,-2,3,-3.....}.( 个)可以得到一个结论,如果这个数是一个奇数,那么一定可以构造出结果为0的数组,偶数不一定.那么我们可以采用容斥原理,用总方案数去减去不符合条件的方案数来计算.
关于偶数,我们可以把它们构造出来的数组看做 (ki为任意数,对于枚举上面的例子很容易想到,偶数个构造数,最后肯定剩下一个a[i]/2,然后因为起点不一定是0,还要加一个不定的k*子数组的个数).
这是选出一个a数组中元素的贡献值,那么选出很多个元素的贡献就是:
(m表示选了m个)
根据题意,我们要满足要求,那么sum就应该等于0.在进行移项:
一次不定方程,这种形式很容易想到裴蜀定理,要让该式子有整数解,那么根据裴蜀定理要满足:
(gcd被后面的值整除)
再变形得到:
要求不符合题意的方案数,也就是不满足这个式子的组合的个数.那么当上述式子右边是奇数时,就不符合条件.
设f(x)为因子2的个数为x的元素的个数.我们在取的这些数组元素中取f(a[i])最小的值中取奇数个时,就肯定是不合法的.因为比它大的数字除以gcd之后肯定得到1,去奇数个的话加起来还是奇数,而f(a[i])比它大的元素因子比它多至少一个因子2,除以gcd之后还是偶数.
所以我们只需要在当前选择的包含有因子2的最小值中,取奇数个元素即可(这样除以2一定是奇数),
组合一下就是在n个球中取比n小的奇数的方案数,也就是中方案,根据乘法原理,求出f(x)最小的组合方案之后,f(x)比它大的元素无论怎么取都会保证在除以gcd之后还是偶数,又根据乘法原理,所以直接乘以后面的取法即可(因子2的数比f(x)大的元素方案数就是
)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N =5e5+10,mod=1e9+7;
int num[40];
int ksm(int x,int y)
{
int res=1;
while(y)
{
if(y&1)
res=res*x%mod;
y>>=1;
x=x*x%mod;
}
return res;
}
void solve()
{
memset(num,0,sizeof num);
int cnt,n,x;
scanf("%lld",&n);
for(int i=1;i<=n;i++)
{
cnt=0;
scanf("%lld",&x);
while(x%2==0)
{
cnt++;
x/=2;
}
if(cnt)
num[cnt]++;
}
int temp,ans=0;
for(int i=1;i<=35;i++)
{
if(!num[i])
continue;
temp=ksm(2,num[i]-1);
for(int j=i+1;j<=35;j++)
temp=temp*ksm(2,num[j])%mod;
ans=(ans+temp)%mod;
}
printf("%lld\n",(ksm(2,n)-1-ans+mod)%mod);
return ;
}
signed main()
{
solve();
return 0;
}