2023牛客暑期多校训练营5
B.Circle of Mistery
题意:有一个由n个点组成的图,现在给出每个点的权值,构造一个排列a,将i与a[i]相连,满足至少有一个从节点1出发的环,其上各点权值之和大于等于k,并且使得排列a中的逆序对数量最少,求出最少的逆序对个数。
Solution
我们考虑到要想尽可能减少逆序对个数,那么其它的点连接方式一定是自环
现在考虑1出发的环上的情况
我们假设从l到r上的点选择一部分作为环,那么在环上有逆序对len-1个,例如234561有5个,243561也是5个,这些贡献全部由1完成
考虑不在环上的点,由于需要跳过某些某些点,比如243561中,3是被跳过的点,环的元素只有24561,跳过一个点的贡献为1,所以跳过x个点的贡献是x,总的贡献就是len-1+x,对于l到r以外的点,是没有贡献的,不会产生逆序对
我们发现,要尽可能使得x小,就必须多加入一些点
对于非负整数来说,我们肯定要加入,他们不会使得权值之和小于k,对于负数来说,我们要尽可能多加入,那么就要多选一些大的负数
void solve()
{
int n,k;cin>>n>>k;
for(int i=1;i<=n;i++)cin>>a[i];
int ans=1e18;
for(int i=1;i<=n;i++)
{
int sum=0,cnt=0;
multiset<int>st;
for(int j=i;j<=n;j++)
{
if(a[j]<0)
{
st.insert(a[j]);
}
else
{
sum+=a[j];
cnt++;
}
if(sum>=k)
{
int temp=sum,tempc=cnt;
for (auto ti = st.rbegin(); ti != st.rend();++ti)
{
int it = *ti;
if(it+temp<k)break;
temp+=it;
tempc++;
}
if(tempc)ans=min(ans,j-i+j-i+1-tempc);
}
}
}
cout<<((ans==1e18)?-1:ans)<<"\n";
}
C.Cheeeeen the Cute Cat
题意:给出一个二分图,求最大匹配
官解看不懂,但是又不能不补,干脆把相关知识补了
按官解说的来
i到j+n有边时,j到i+n没有边,所以可以看成从i到j的一条边
这样就有n个点和n\(\times\)(n-1)/2,这是一张无向完全图
无向完全图可以通过给予方向来转变为有向完全图,有向完全图又称为竞赛图
哈密顿回路:经过每个点一次且仅经过一次并回到起点的路径
竞赛图的性质:任何一个竞赛图都有哈密顿回路,并且如果存在环,一定有三元环。
对于一个普通的有向图:如果它有哈密顿回路,则一定有强连通分量
D.Cirno's Perfect Equation Class
题意:给出k,c,n,已知ka+b=c,a>0,b>0,并且b=xc(x>=1),要求求出满足gcd(a,b)>=n的x的个数
Solution
居然是模拟...
void solve()
{
int k,c,n;cin>>k>>c>>n;
int ans=0;
for(int i=1;i*i<=c;i++)
{
if(c%i!=0)continue;
int t=c-c/i;
if(t%k==0)
{
int a=t/=k;
int b=c/i;
if(a>0&&b>0&&gcd(a,b)>=n)ans++;
}
t=c-i;
if(t%k==0)
{
int a=t/k;
int b=i;
if(a>0&&b>0&&gcd(a,b)>=n)ans++;
}
}
cout<<ans<<"\n";
}
E.Red and Blue and Green
题意:构造一个排列,限制在m个不同的区间中区间内的逆序对个数的奇偶性,其中不同的区间要么相互包含要么不相交
Solution
由于区间的性质,我们可以考虑把他们看成一棵树,遍历对树进行dfs
如果当前是根节点,并且限制为奇数,则交换开头元素即可
如果当前不是根节点,我们可以交换r和r+1的位置,因为r一定比后面的小,所以只会对整个区间的逆序对产生影响,而不会对其子区间产生影响,也可以交换l-1和l的位置
int a[N];
struct node
{
int l,r,op;
bool operator <(const node &t)const &{
if(r-l!=t.r-t.l)return r-l<t.r-t.l;
return l<t.l;
}
};
vector<node>v;
vector<int>e[N];
int vis[N];
int b[N];
bool cmp(int x,int y)
{
return v[x].l<v[y].l;
}
void dfs(int x)
{
if(e[x].size()==0)
{
if(v[x].op==1)swap(a[v[x].l],a[v[x].l+1]);
return;
}
sort(e[x].begin(),e[x].end(),cmp);
int sum=0;
for(auto it:e[x])
{
dfs(it);
sum+=v[it].op;
}
//cout<<sum<<"\n";
if((sum%2)!=v[x].op)
{
if(v[e[x][0]].l==v[x].l)
{
swap(a[v[e[x][0]].r],a[v[e[x][0]].r+1]);
}else
{
swap(a[v[e[x][0]].l-1],a[v[e[x][0]].l]);
}
}
}
void solve()
{
int n,m;cin>>n>>m;
for(int i=1;i<=n;i++)a[i]=i;
for(int i=1;i<=m;i++)
{
int x,y,z;cin>>x>>y>>z;
if(x==y&&z!=0)
{
cout<<"-1\n";
return;
}
if(x!=y)v.push_back({x,y,z});
}
sort(v.begin(),v.end());
for(int i=0;i<v.size();i++)
{
for(int j=i+1;j<v.size();j++)
{
if(v[j].l<=v[i].l&&v[i].r<=v[j].r)
{
e[j].push_back(i);
vis[i]=1;
break;
}
}
}
for(int i=0;i<v.size();i++)
{
if(!vis[i])dfs(i);
}
for(int i=1;i<=n;i++)b[a[i]]=i;
for(int i=1;i<=n;i++)cout<<b[i]<<" \n"[i==n];
}
G.Go to Play Maimai DX
题意:有一个数组a,只有1,2,3,4,最长的至少有1个1,1个2, 1个3和k个4的区间是多长
Solution
前缀和二分即可
int a[N];
int b[N][5];
int n,k;
bool check(int i,int x)
{
for(int j=1;j<=3;j++)
{
if(b[x][j]-b[i-1][j]<1)return false;
}
return (b[x][4]-b[i-1][4]>=k);
}
void solve()
{
cin>>n>>k;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)
{
for(int j=1;j<=4;j++)
{
b[i][j]=b[i-1][j];
}
b[i][a[i]]++;
}
int ans=INF;
for(int i=1;i<=n;i++)
{
int l=i,r=n;
while(l<r)
{
int mid=(l+r)>>1;
if(check(i,mid))r=mid;
else l=mid+1;
}
if(check(i,l))ans=min(l-i+1,ans);
}
cout<<ans<<"\n";
}
H.Nazrin the Greeeeeedy Mouse
题意:纳兹琳有m个包,一个比一个大,她家在一条长为n的路上,家在点1,每两个点之间有一个奶酪,每个奶酪有一个大小a和重量b,她如果想从x点到x+1点,要么给奶酪上面打一个洞,要么拿走奶酪,问她总共最多能拿多重的奶酪
Solution
很显然背包问题,但是m很大,考虑到其实m个包一个比一个大,而n又比m小,所以我们只用拿最大的包即可
然后定义dp[i][j]为到用前i个包到第j个点所能获得的奶酪重量之和的最大值
显然
f[i][j][k]表示第i个包在区间[j,k]能获得的奶酪重量之和的最大值,这个可以预处理得到
通过前缀和处理还可以把第一维给优化掉
int dp[205][2];
int f[205][205][205];
int a[205],b[205];
int sz[N];
void solve()
{
int n,m;cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i]>>b[i];
for(int i=1;i<=n;i++)
{
for(int j=i;j<=n;j++)
{
for(int k=200;k>=0;k--)
{
f[k][i][j]=f[k][i][j-1];
if(k>=a[j])f[k][i][j]=max(f[k][i][j],f[k-a[j]][i][j-1]+b[j]);
}
}
}
for(int i=1;i<=m;i++)cin>>sz[i];
int op=0;
for(int i=1;i<=n;i++)dp[i][0]=f[sz[max(0LL,m-n)+1]][1][i];
op^=1;
for(int i=max(0LL,m-n)+2;i<=m;i++)
{
for(int k=1;k<=n;k++)
{
dp[k][op]=dp[k][op^1];
for(int j=k-1;j>=0;j--)
{
dp[k][op]=max(dp[k][op],dp[j][op^1]+f[sz[i]][j+1][k]);
}
}
op^=1;
for(int j=0;j<=200;j++)dp[j][op]=0;
}
cout<<dp[n][op^1]<<"\n";
}
I.The Yakumo Family
题意:给出一个序列a,求sum
其中XOR(l,r)表示序列a在区间[l,r]内的异或和
Solution
对于每一个二进制位上的数,其贡献都是独立的,我们把它拆开来看
先处理出前缀异或和
先看\(\sum\)XOR(\(l_1\),\(r_1\)),对于第k位上的数来说,其对答案的贡献为(1<<k)\(\times\)(前面与它第k位不同的数的个数)
再看\(\sum\)XOR(\(l_1\),\(r_1\))\(\times\)\(\sum\)XOR(\(l_2,r_2\)),这上面的第k位的贡献为(1<<k)\(\times\)(前面与它第k位不同的数的个数\(\times\)(这个不同的数的前面的\(\sum\)XOR(\(l_1\),\(r_1\))的对答案的贡献))
最后同理可以求出\(\sum\)XOR(\(l_1\),\(r_1\))\(\times\)\(\sum\)XOR(\(l_2,r_2\))\(\times\)\(\sum\)XOR(\(l_3,r_3\))
void solve()
{
int n;cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
int res=0;
for(int i=1;i<=n;i++)
{
res^=a[i];
s[i]=res;
t[i]=1;
}
int sum=0;
for(int k=1;k<=3;k++)
{
for(int j=0;j<=30;j++)
{
cnt[0]=1,cnt[1]=0;
if(k!=1)cnt[0]=0;
for(int i=1;i<=n;i++)
{
ans[i]=(ans[i]+((cnt[((s[i]>>j)&1)^1])<<j)%mod)%mod;
cnt[(s[i]>>j)&1]=(cnt[(s[i]>>j)&1]+t[i])%mod;
}
}
for(int i=1;i<=n;i++)t[i]=(t[i-1]+ans[i])%mod;
for(int i=1;i<=n;i++)ans[i]=0;
}
cout<<t[n]<<"\n";
}

浙公网安备 33010602011771号