2021牛客暑期多校训练营1
G
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-laWrTX4D-1627219079381)(C:\Users\wxy\AppData\Roaming\Typora\typora-user-images\image-20210721144108389.png)]
首先需要了解的是题目需要我们输出的是绝对值的差值,在abs运算中一定是大数去减去小数的,所以题目是有一个隐藏的无限制的次数的操作,就是交换a,b序列中相同位置的值。所以为了方便理解可以将a序列看做大数序列,b序列看作小数序列。
现在我们进行k次操作,使得答案的值变大。那么在什么时候答案的值会变大呢?
如果b序列中的某个数bi,比a序列中的某个数aj要大的话,那么显然将bi和aj互换的话,答案是会变大的。因为是2个较大的数在相减,和2个较小的数相减,我们的目的是要较大的数减去较小的数,这些答案就会是最优。
那么答案增加了多少呢,ai-bi+aj-bj =>bi-aj+ai-aj 发现增加了2*(bj-ai);
那么我们只需要将大数和小数排序,如果发现有小数大于大数的话,就答案增加。如果序列已经是最有的话,那么就不需要再去交换大小数了,要及时break;
如果我们已经break后,k还没用完怎么办?我们只需要随意在同一个序列中交换就可以,最后的答案是不会改变的。
int a[5 * maxn], b[5 * maxn];
int dmin[5 * maxn], dmax[5 * maxn];
signed main()
{
//ios::sync_with_stdio(0);
//cin.tie(0),cout.tie(0);
int n = read(), k = read();
rep(i, 1, n) a[i] = read();
rep(i, 1, n) b[i] = read();
ll ans = 0;
rep(i, 1, n)
{
ans = ans + abs(a[i] - b[i]);
dmax[i] = 2 * max(a[i], b[i]);
dmin[i] = 2 * min(a[i], b[i]);
}
sort(dmax + 1, dmax + 1 + n);
sort(dmin + 1, dmin + 1 + n, greater<int>());
for (int i = 1; i <= n && i <= k; ++i)
{
if (dmin[i] < dmax[i]) break;
ans = ans + dmin[i] - dmax[i];
}
out(ans);
return 0;
}
A
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mGkhrLJc-1627219079383)(C:\Users\wxy\AppData\Roaming\Typora\typora-user-images\image-20210721150107248.png)]
本题SG打表太慢了…
一个很重要的结论就是,如果某堆石子为i的话,那么另外一堆石子只会有一种情况满足后手胜利。
证:
设( i , p ) 和(i,q)都为选择一次后手胜利且p>q,则先手可以从i,p转移到i,q,而得到先手胜,与假设矛盾。
所以可以利用这个结论来愉快的打表,知道先手必败的状态,可以反向得到后手必胜的状态。
sg[0][0] = 0;
for(int i = 0;i<=5000;++i)
for(int j = 0;j<=5000;++j)
{
if(!sg[i][j])
{
for(int k = 1;i+k<=5000;++k)
for(int s = 0;j+s*k<=5000;++s)
sg[i+k][j+s*k] = 1;
for(int k = 1;j+k<=5000;++k)
for(int s = 0;i+s*k<=5000;++s)
sg[i+s*k][j+k] = 1;
}
}
这个打表看起来是一个n^3的时间,但是!sg[i] [j]只会有5000个(结论),而枚举倍速是logn的时间
所以实际上是一个n^2logn的时间复杂度。
D
kmp签到
signed main()
{
//ios::sync_with_stdio(0);
//cin.tie(0),cout.tie(0);
int n = read(),m = read();
rep(i,0,n-1) cin>>a[i];
cin>>b;
int len = b.size();
string c = "";
rep(i,1,len) c = '0'+c;
int cnt = 0;
rep(i,0,n-1)
{
int pos = 0;
while( (pos = a[i].find(c,pos)) != -1)
{
cnt++;
pos++;
}
}
out(cnt);
return 0;
}
B
签到
signed main()
{
//ios::sync_with_stdio(0);
//cin.tie(0),cout.tie(0);
double r,a,b,h;
cin>>r>>a>>b>>h;
if(2*r<=b)
{
puts("Drop");
}
else
{
double x = b/(a-b)*h;
double xie = sqrt(b*b/4+x*x);
double l = 2*r*xie/b;
puts("Stuck");
printf("%.9lf\n",l-x);
}
return 0;
}
F
做过铁签到
vector<int>no;
signed main()
{
//ios::sync_with_stdio(0);
//cin.tie(0),cout.tie(0);
no.push_back(1);
no.push_back(2);
no.push_back(4);
no.push_back(5);
no.push_back(7);
no.push_back(8);
rep(i,11,98)
{
int ge = i%10;
int shi = i/10;
if(((ge+shi) % 3 !=0) && (ge%3) !=0 && (shi%3) != 0 )
no.push_back(i);
}
int t = read();
while(t--)
{
ll l = read(),r = read();
if(l >= 100) out(r-l+1);
else
{
ll ans = r - l + 1;
for(auto x : no)
{
if(x >= l && x<=r) ans--;
}
out(ans);
}
}
return 0;
}
k
int b[1010];
int n;
double fo[1010];
double dod(int x,int y)
{
return fo[abs(x-y)];
}
void solve()
{
rep(i,0,n-1)
rep(j,i+1,n-1)
if(dod(i,b[i]) + dod(j,b[j]) > dod(i,b[j]) + dod(j,b[i]))
swap(b[i],b[j]);
}
signed main()
{
IOS;
//inout.txt;
rep(i,1,1010)
{
fo[i] = sqrt(i);
}
int t;
cin>>t;
while(t--)
{
cin>>n;
rep(i,0,n-1)
cin>>b[i];
sort(b,b+n);
rep(i,1,15) solve();
rep(i,0,n-2)
{
cout<<b[i]<<" ";
}
cout<<b[n-1]<<'\n';
}
return 0;
}
I
int qmi(int a,int b)
{
int res=1;
while(b)
{
if(b&1)res=(LL)res*a%M;
a=(LL)a*a%M;
b>>=1;
}
return res;
}
int a[N],cnt1[N],s1[N],cnt2[N],s2[N],inv[N],n,f;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i],inv[i]=qmi(i,M-2);
for(int i=n;i>=0;i--)
for(int j=n;j>=0;j--)
{
if(i==j&&i&&j)continue;
if(a[i]>a[j])
{
f=cnt1[i]?(1+(LL)inv[cnt1[i]]*s1[i])%M:1;
cnt2[j]++,s2[j]=(s2[j]+f)%M;
}
else
{
f=cnt2[j]?(1+(LL)inv[cnt2[j]]*s2[j])%M:1;
cnt1[i]++,s1[i]=(s1[i]+f)%M;
}
}
cout<<(f-1+M)%M<<"\n";
return 0;
}
J
struct node{
int u,v,w;
bool f;
}tree[N*4];
node p_up(node l,node r,int cost)
{
node ans;
ans.f= l.f&r.f;
if(l.u+cost > r.v) ans.f=0;
ans.u=max(r.u,l.u+cost+r.w);
ans.v=min(l.v,r.v-cost-l.w);
ans.w=l.w+r.w+cost;
return ans;
}
void build(int rt,int l,int r)
{
if(l==r)
{
tree[rt]={u[l],v[l],0,true};
return ;
}
int mid=(l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
tree[rt]=p_up(tree[ls],tree[rs],cost[mid]);
}
void update(int rt,int l,int r,int x)
{
if(l==r)
{
tree[rt]={u[l],v[l],0,true};
return ;
}
int mid=(l+r)>>1;
if(x<=mid) update(ls,l,mid,x);
else update(rs,mid+1,r,x);
tree[rt]=p_up(tree[ls],tree[rs],cost[mid]);
}
node query(int rt,int l,int r,int L,int R)
{
if(L<=l&&r<=R)
return tree[rt];
int mid = (l+r)>>1;
if(R<=mid)
return query(ls,l,mid,L,R);
else if(L>mid)
return query(rs,mid+1,r,L,R);
else
return p_up(query(ls,l,mid,L,R),query(rs,mid+1,r,L,R),cost[mid]);
}
int main()
{
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
scanf("%d",&u[i]);
for(int i=1;i<=n;i++)
scanf("%d",&v[i]);
for(int i=1;i<n;i++)
scanf("%d",&cost[i]);
build(1,1,n);
int q;
cin>>q;
while(q--)
{
int op;cin>>op;
if(op==0)
{
int l,r;
scanf("%d%d",&l,&r);
node ans = query(1,1,n,l,r);
if(ans.f) puts("Yes");
else puts("No");
}
else if(op==1)
{
int pos;
scanf("%d",&pos);
scanf("%d",&cost[pos]);
update(1,1,n,pos);
}
else
{
int pos;
scanf("%d",&pos);
scanf("%d%d",&u[pos],&v[pos]);
update(1,1,n,pos);
}
}
}
}