Codeforces Round #539 (Div. 2)(题解)
A. Sasha and His Trip
题目大意
一辆车在一条直线上行驶,在坐标i的油价为i,每次车厢内最多装载v升汽油,一升汽油可以从i城到i+1城,问行驶到n城最少多少费用
解题思路
在城市1直接把油箱买满,只要剩余的油不够跑完剩下来的路就每跑一个城市买一次油
AC代码
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,v;
cin>>n>>v;
int ans=0;
for(int i=2;i<=n-v;i++)
{
ans+=i;
}
ans+=v;
if(v>=n-1) ans=n-1;
cout<<ans<<endl;
}
B. Sasha and Magnetic Machines
题目大意
给出n个数,可任意选择一对数 使得有任意的满足 的x对这两个数变换成 ,问如何进行上述的操作一次,使得变换后 尽可能小
解题思路
所以只需要提前处理出1,100之间任意的两对数进行上述变换可以减小的数值,对所有出现的数进行上述处理即可
AC代码
#include<bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;
int in[105][105];
int cnt[105];
int main()
{
memset(in,0,sizeof(inf));
for(int i=1;i<=100;i++)
for(int j=1;j<=100;j++)
{
for(int k=2;k<=i;k++)
{
if(i%k==0)
{
in[i][j]=max(in[i][j],i+j-i/k-j*k);
}
}
}
int n;
cin>>n;
int ans=0;
int x;
while(n--) cin>>x,cnt[x]++,ans+=x;
int d=0;
for(int i=1;i<=100;i++)
{
if(!cnt[i]) continue;
cnt[i]--;
for(int j=1;j<=100;j++)
{
if(cnt[j]) d=max(d,in[i][j]);
}
cnt[i]++;
}
cout<<ans-d<<endl;
}
C. Sasha and a Bit of Relax
题目大意
给出一段序列,问存在多少段长度为偶数的序列使得序列前半段的的异或和等于后半段
解题思路
只要一段区段的异或和为0,且区段长度为偶数,则一定满足上述条件,由于一个数异或0依然等于0,故,只需要处理出前缀异或和,对下标奇偶相同的且相同的前缀的即使所求的一段区段
AC代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
unordered_map<int,int> mp[2];
const int size=3e5+5;
int arr[size];
int d[size];
int32_t main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++) cin>>arr[i];
d[0]=0;
for(int i=1;i<=n;i++) d[i]=d[i-1]^arr[i];
int ans=0;
int t;
for(int i=0;i<=n;i++)
{
t=(i%2);
if(mp[t].count(d[i])) ans+=mp[t][d[i]];
if(mp[t].count(d[i]))mp[t][d[i]]++;
else mp[t][d[i]]=1;
}
cout<<ans<<endl;
}
D. Sasha and One More Name
题目大意
给出一段回文串,问最少对其剪切几次后进行重新拼接可以形成新的回文串
解题思路
由于原串为回文串,故最多进行2次剪切.由此进行暴力枚举即可
AC代码
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
char s[100000],t[100000];
int main(){
cin>>s;
int i,j,k,l,r,n=strlen(s),ans=0;
for(i=1;i<n;i++) if(s[i]!=s[0]) ans=1;
if(ans==0) cout<<"Impossible"<<endl;
else{
for(i=1;i<n;i++){
k=0;
for(j=i;j<n;j++) t[k++]=s[j];
for(j=0;j<i;j++) t[k++]=s[j];
int x=1;
for(j=0;j<n;j++) if(t[j]!=s[j]) x=0;
if(x) continue;
l=0;
r=n-1;
int flag=1;
while(l<=r){
if(t[l]!=t[r]) flag=0;
l++;
r--;
}
if(flag){
cout<<1<<endl;
return 0;
}
}
if(n%2){
k=n/2;
int a=0;
for(i=k-1;i>=1;i--) if(s[i]!=s[0]) a=1;
if(a==0) cout<<"Impossible"<<endl;
else cout<<2<<endl;
}
else cout<<2<<endl;
}
}
F. Sasha and Interesting Fact from Graph Theory
题目大意
给出n个点,由这些点连成一棵树,树中每一条边的权重介于 给出两点a,b问有多少种树满足a,b之间的路径的权值之和为m
解题思路
假设给定的ab之间假设存在条边,则这n条边为了满足条件则有 种权重分配方式,除了两端的a,b共有选点方式有 种分配方式,再对选出的点进行全排列则须再乘上 满足ab之间的边之后剩余的所有的边的的权重任意 接下来需要将剩下来的 个点接到这个ab路径上
为此需要引入凯利公式.以下引自wiki:
设
为n个有标号点分成k个连通块的的分割种数,其中节点1,2,3,…k属于不同的联通块
由此枚举所有的
即可得出答案
AC代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int size=1e6+5;
const int mod=1e9+7;
int fac[size];
int invfac[size];
int quick_pow(int a,int b)
{
a=a%mod;
int ans=1;
while(b)
{
if(b&1) ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
void init()
{
fac[0]=1;
fac[1]=1;
for(int i=2;i<size;i++) fac[i]=fac[i-1]*i%mod;
invfac[size-1]=quick_pow(fac[size-1],mod-2);
for(int i=size-2;i>=0;i--)
invfac[i]=invfac[i+1]*(i+1)%mod;
}
inline int C(int n,int m){return ((fac[n]*invfac[n-m]%mod)*invfac[m])%mod;}
inline int A(int n,int m){return fac[n]*invfac[n-m]%mod;}
int32_t main()
{
int n,m;
int a,b;
cin>>n>>m>>a>>b;
init();
int ans=0;
for(int i=1;i<=m;i++)
{
int vcnt=i+1,ecnt=i;
if(vcnt>n) break;
if(vcnt==n) ans=(ans+C(m-1,ecnt-1)*fac[vcnt-2]%mod)%mod;
else ans=(ans+C(n-2,vcnt-2)*C(m-1,ecnt-1)%mod*fac[vcnt-2]%mod*quick_pow(m,n-1-ecnt)%mod*vcnt%mod*quick_pow(n,n-vcnt-1))%mod;
}
cout<<ans<<endl;
}