上次的Codeforces Global Round 18给人整麻了,于是理智的选择了咕咕咕(bushi),看之后的心情更新了。。。。。。
这场总体感觉题目不错,可惜E想歪了,看了T神的E表示人麻了,居然是个暴力+贪心(生无可恋)
PS:中间打的时候还有点小插曲,做完A后看了下C感觉蛮简单的,但写臭了debug了20分钟,心态炸裂,导致B写的慢了。。。
A. Closing The Gap(摸你)
存在两种情况能够满足
1.a+b==c
2.a==b && c%2==0
(写的比较拉)
#include <bits/stdc++.h>
#define ll long long
#define ls p<<1
#define rs p<<1|1
#define Ma 1000005
#define mod 1000000007
using namespace std;
int main()
{
ll tt;
scanf("%lld",&tt);
while (tt--)
{
ll a,b,c;
scanf("%lld%lld%lld",&a,&b,&c);
if (a==b&&c%2==0)
printf("YES\n");
else if (a==c&&b%2==0)
printf("YES\n");
else if (b==c&&a%2==0)
printf("YES\n");
else if ((a+b+c)==max(max(a,b),c)*2)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}
B. Berland Music(贪心)
设cnt0为0的个数,对于0的打分情况为[1,cnt0],对于0来说最小贡献w0为,其中p为升序的0的原得分,同理对于1也成立,因此排序赋值即可。
#include <bits/stdc++.h>
#define ll long long
#define ls p<<1
#define rs p<<1|1
#define Ma 1000005
#define mod 1000000007
using namespace std;
struct node
{
ll w,num,p,ans;
}t[Ma];
bool cmp1(node x,node y)
{
return x.w<y.w;
}
bool cmp2(node x,node y)
{
return x.num<y.num;
}
int main()
{
ll tt;
scanf("%lld",&tt);
while (tt--)
{
ll n;
scanf("%lld",&n);
for (ll i=0;i<n;i++)
scanf("%lld",&t[i].w),t[i].num=i;
string s;
cin>>s;
for (ll i=0;i<s.size();i++)
t[i].p=s[i]-'0';
sort(t,t+n,cmp1);
ll add=1;
for (ll i=0;i<n;i++)
if (t[i].p==0)
t[i].ans=add,add++;
for (ll i=0;i<n;i++)
if (t[i].p==1)
t[i].ans=add,add++;
sort(t,t+n,cmp2);
for (ll i=0;i<n;i++)
printf("%lld ",t[i].ans);
printf("\n");
}
return 0;
}
C. Set or Decrease(贪心)
我们发现最优解一定是对数组中的min进行p次操作1(-1),再进行q次操作2(ai=min)
我们可以固定q的次数,求出所需的最小p,那么结果为p+q,只需求出最小的p+q即可
PS:p,q>=0
#include <bits/stdc++.h>
#define ll long long
#define ls p<<1
#define rs p<<1|1
#define Ma 1000005
#define mod 1000000007
using namespace std;
ll a[Ma];
int main()
{
ll tt;
scanf("%lld",&tt);
while (tt--)
{
ll n,k;
scanf("%lld%lld",&n,&k);
ll sum=0;
for (ll i=1;i<=n;i++)
scanf("%lld",&a[i]),sum+=a[i];
sort(a+1,a+n+1);
ll ans=sum-k,add=1;//add-1为2的操作次数,ans为p+q
sum-=a[1];
for (ll i=n;i>=2;i--)
{
add++;
sum-=a[i];
ll p;//p代表所需的(a[1]/min)的最大值
if (k-sum>=0)
p=(k-sum)/add;
else
p=(k-sum-add+1)/add;
if (p>a[1])
p=a[1];
ans=min(ans,(a[1]-p)+add-1);
}
if (ans<0)
ans=0;
printf("%lld\n",ans);
}
return 0;
}
D. Shuffle (数学+排组+容斥)
假设我们可以找出cnt段这样的最优子串,对于第i串为l[i]-r[i],我们运用容斥原理可以得出
ans=(p1+.....+pn)-(p1p2+.......)+(p1p2p3+...)........
对于实际=,其中
因此ans=(p1+.....+pn)-( p1p2+ p2p3+ p3p4......)
上面内容比较抽象,可以画图理解下。。。。。
#include <bits/stdc++.h>
#define ll long long
#define ls p<<1
#define rs p<<1|1
#define Ma 1000005
#define mod 998244353
using namespace std;
ll l[Ma],r[Ma],tot;
ll a[Ma];
ll mul[Ma],pre[Ma];
ll po(ll p,ll x=mod-2)
{
ll sum=1;
while (x)
{
if (x&1)
sum*=p,sum%=mod;
p*=p,p%=mod;
x>>=1;
}
return sum;
}
void pri()
{
mul[0]=pre[0]=1;
for (ll i=1;i<Ma;i++)
mul[i]=mul[i-1]*i%mod,pre[i]=po(mul[i]);
return;
}
ll C(ll x,ll y)
{
if (x<0||y<0||x>y)
return 0;
return mul[y]*pre[x]%mod*pre[y-x]%mod;
}
int main()
{
pri();
ll n,k;
scanf("%lld%lld",&n,&k);
string s;
cin>>s;
tot=0;
for (ll i=0;i<n;i++)
if (s[i]=='1')
a[++tot]=i;
a[0]=-1,a[tot+1]=n;
if (tot<k||k==0)
printf("1\n");
else
{
ll ans=0,add=0;
for (ll i=0;i<=tot-k;i++)
l[++add]=a[i]+1,r[add]=a[i+k+1]-1;
for (ll i=1;i<=add;i++)
ans=(ans+C(k,r[i]-l[i]+1))%mod;
for (ll i=2;i<=add;i++)
ans=(ans-C(k-1,r[i-1]-l[i]+1))%mod;
ans=(ans+mod)%mod;
printf("%lld\n",ans);
}
return 0;
}
E. Math Test(贪心+sort)
赛中想的是用神仙(瞎jb乱搞)sort解决,看了T神的code后发现也确实是用神仙sort解决
首先将拆开,得出ans=sgni*xi-sgni*ri,其中sgni=(xi>ri)?-1:1,而对于sgni*ri我们可以用贪心将其最大化,而我们只需遍历sgni的符号即可。
复杂度:O()
PS:确实挺难想的,可能这种类型题目碰见的比较少,赛中真没想到,但并不难
#include <bits/stdc++.h>
#define ll int
#define ls p<<1
#define rs p<<1|1
#define Ma 10005
#define mod 1000000007
using namespace std;
ll a[Ma];
ll n,m;
string s[100];
ll pri[Ma],ma=0;
struct node
{
ll ans,p[Ma];
bool operator <(const node &A)const{
return ans>A.ans;
}
}t[1<<10];
struct wei
{
ll num,w;
bool operator <(const wei &A)const{
return w>A.w;
}
}add[Ma];
int main()
{
ll tt;
scanf("%d",&tt);
while (tt--)
{
ma=0;
scanf("%d%d",&n,&m);
for (ll i=0;i<n;i++)
scanf("%d",&a[i]);
for (ll i=0;i<n;i++)
cin>>s[i];
for (ll q=0;q<(1<<n);q++)
{
t[q].ans=0;
for (ll i=0;i<m;i++)
add[i].w=0,add[i].num=i+1;
for (ll i=0;i<n;i++)
{
ll sgn;
if (q&(1<<i))
sgn=1;
else
sgn=-1;
t[q].ans-=sgn*a[i];
for (ll j=0;j<m;j++)
if (s[i][j]=='1')
add[j].w+=sgn;
}
sort(add,add+m);
for (ll j=0;j<m;j++)
{
t[q].p[add[j].num]=m-j;
t[q].ans+=add[j].w*(m-j);
}
if (t[q].ans>=ma)
{
ma=t[q].ans;
for (ll i=1;i<=m;i++)
pri[i]=t[q].p[i];
}
}
for (ll i=1;i<=m;i++)
printf("%d ",pri[i]);
printf("\n");
}
return 0;
}