A. Sasha and His Trip
题意:
从1号城市到n号城市,每过一个城市消耗一升油,在i城市加油的代价为i每升。油箱最多v升油,问到n号城市的最小代价。
题解:
在最前面几个城市加最多的油,最后一段路不加油刚好到n号城市。需要注意v>=n的情况。
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>
#include <string>
#include <stack>
#include <cctype>
#include <vector>
#include <queue>
#include <set>
#include <utility>
#include <cassert>
#include <iomanip>
#include <deque>
#include <time.h>
#include <bitset>
using namespace std;
#define ll long long
#define maxn 500005
#define mod 1000000007
#define MOD 998244353
#define Mod 1000000009
#define eps 1e-10
const ll inf=0x3f3f3f3f3f3f3f3f;
const ll INF=0x3f3f3f3f;
const ll mod1=1e9+7;
const ll mod2=1e9+9;
template <typename T>
inline void read(T& X) {X = 0; int w = 0; char ch = 0;while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();if (w) X = -X;}
char F[200];inline void write(int x){if(x == 0){putchar('0');return;}int tmp = x > 0 ? x : -x;int cnt = 0;if(x < 0)putchar( '-' );while(tmp > 0){F[cnt++] = tmp % 10 + '0';tmp /= 10;}while(cnt > 0)putchar(F[--cnt]) ;}
template<typename T> void print(T x){if(x>9) print(x/10);putchar(x%10+'0');}
ll q_pow(ll x,ll y,ll M){ll ans=1;while(y){if(y%2){y--;ans=ans*x%M;}else {y/=2;x=x*x%M;}}return ans;}
int main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int n,v;
cin>>n>>v;
int vv=0;
int ans=0;
if(v>=n)v=n-1;
for(int i=1;i<=n;i++){
if(i+vv<n){
ans+=i*(v-vv);
vv=v;
}
vv--;
}
cout<<ans;
return 0;
}
B. Sasha and Magnetic Machines
题意:
你有n个数,你可以对一个数除以
x
,
(
x
∣
a
i
)
x,(x|a_i)
x,(x∣ai)另一个数
∗
x
*x
∗x,并且你只能操作一次,问n个数的和最小为多少。
题解:
对于乘操作,我们肯定给最小的数乘,使得加的最小,然后我们发现数字很小只有100,直接暴力枚举所有的情况。
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>
#include <string>
#include <stack>
#include <cctype>
#include <vector>
#include <queue>
#include <set>
#include <utility>
#include <cassert>
#include <iomanip>
#include <deque>
#include <time.h>
#include <bitset>
using namespace std;
#define ll long long
#define maxn 500005
#define mod 1000000007
#define MOD 998244353
#define Mod 1000000009
#define eps 1e-10
const ll inf=0x3f3f3f3f3f3f3f3f;
const ll INF=0x3f3f3f3f;
const ll mod1=1e9+7;
const ll mod2=1e9+9;
template <typename T>
inline void read(T& X) {X = 0; int w = 0; char ch = 0;while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();if (w) X = -X;}
char F[200];inline void write(int x){if(x == 0){putchar('0');return;}int tmp = x > 0 ? x : -x;int cnt = 0;if(x < 0)putchar( '-' );while(tmp > 0){F[cnt++] = tmp % 10 + '0';tmp /= 10;}while(cnt > 0)putchar(F[--cnt]) ;}
template<typename T> void print(T x){if(x>9) print(x/10);putchar(x%10+'0');}
ll q_pow(ll x,ll y,ll M){ll ans=1;while(y){if(y%2){y--;ans=ans*x%M;}else {y/=2;x=x*x%M;}}return ans;}
int n;
int a[maxn];
int main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
sort(a+1,a+1+n);
ll sum=0;
for(int i=1;i<=n;i++)sum+=a[i];
ll ans=sum;
for(int i=2;i<=n;i++){
for(int j=2;j<=a[i];j++){
if(a[i]%j==0){
ans=min(ans,sum-a[i]-a[1]+a[1]*j+a[i]/j);
}
}
}
cout<<ans;
return 0;
}
C. Sasha and a Bit of Relax
题意:
若[l,r]和[r+1,r+r-l]两段的区间异或和相等,就是一个好的方案,问共有多少个。
题解:
两个区间异或和相同,等价于两个区间异或为0,只需要求有多少个前缀异或值等于当前值,遍历一遍求和就行了。
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>
#include <string>
#include <stack>
#include <cctype>
#include <vector>
#include <queue>
#include <set>
#include <utility>
#include <cassert>
#include <iomanip>
#include <deque>
#include <time.h>
#include <bitset>
using namespace std;
#define ll long long
#define maxn 500005
#define mod 1000000007
#define MOD 998244353
#define Mod 1000000009
#define eps 1e-10
const ll inf=0x3f3f3f3f3f3f3f3f;
const ll INF=0x3f3f3f3f;
const ll mod1=1e9+7;
const ll mod2=1e9+9;
template <typename T>
inline void read(T& X) {X = 0; int w = 0; char ch = 0;while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();if (w) X = -X;}
char F[200];inline void write(int x){if(x == 0){putchar('0');return;}int tmp = x > 0 ? x : -x;int cnt = 0;if(x < 0)putchar( '-' );while(tmp > 0){F[cnt++] = tmp % 10 + '0';tmp /= 10;}while(cnt > 0)putchar(F[--cnt]) ;}
template<typename T> void print(T x){if(x>9) print(x/10);putchar(x%10+'0');}
ll q_pow(ll x,ll y,ll M){ll ans=1;while(y){if(y%2){y--;ans=ans*x%M;}else {y/=2;x=x*x%M;}}return ans;}
int n;
int sum[maxn];
int a[maxn];
map<ll,ll>mp[2];
int main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++){
sum[i]=sum[i-1]^a[i];
}
ll ans=0;
mp[0][0]=1;
for(int i=1;i<=n;i++){
ans+=mp[i%2][sum[i]];
mp[i%2][sum[i]]++;
}
cout<<ans;
return 0;
}
D. Sasha and One More Name
题意:
给你一串回文串,你可以将他们切成k+1段,然后拼成一个不等于原回文串的回文串。问最少需要切几次,或者不可能做到。
题解:
字符串原本就是回文串,我们找一个长度相同的前缀和后缀,若两个不相等,我们切两刀,将两个交换就是一个合法答案。若不存在这样的方案,递推我们可以得出,[1,len/2]区间内的字符完全一样。特判下这种情况是无解的,或者len==1也是无解的。然后除了无解的情况,ans<=2,枚举1刀的情况,若没有方案ans=2,若有ans=1;
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>
#include <string>
#include <stack>
#include <cctype>
#include <vector>
#include <queue>
#include <set>
#include <utility>
#include <cassert>
#include <iomanip>
#include <deque>
#include <time.h>
#include <bitset>
using namespace std;
#define ll long long
#define maxn 1000005
#define mod 1000000007
#define MOD 998244353
#define Mod 1000000009
#define eps 1e-10
const ll inf=0x3f3f3f3f3f3f3f3f;
const ll INF=0x3f3f3f3f;
const ll mod1=1e9+7;
const ll mod2=1e9+9;
template <typename T>
inline void read(T& X) {X = 0; int w = 0; char ch = 0;while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();if (w) X = -X;}
char F[200];inline void write(int x){if(x == 0){putchar('0');return;}int tmp = x > 0 ? x : -x;int cnt = 0;if(x < 0)putchar( '-' );while(tmp > 0){F[cnt++] = tmp % 10 + '0';tmp /= 10;}while(cnt > 0)putchar(F[--cnt]) ;}
template<typename T> void print(T x){if(x>9) print(x/10);putchar(x%10+'0');}
ll q_pow(ll x,ll y,ll M){ll ans=1;while(y){if(y%2){y--;ans=ans*x%M;}else {y/=2;x=x*x%M;}}return ans;}
int main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
string s;
cin>>s;
if(s.length()==1){
cout<<"Impossible";
return 0;
}
int num=0;
for(int i=0;i<s.length()/2;i++){
if(s[i]==s[0])num++;
}
if(num==s.length()/2){
cout<<"Impossible";
return 0;
}
int f=0;
for(int i=1;i<s.length()-1;i++){
string s1=s.substr(0,i);
string s2=s.substr(i,s.length()-i);
string s3=s2+s1;
string s4=s3;
reverse(s4.begin(),s4.end());
if(s3==s4&&s3!=s){
f=1;
break;
}
}
if(f)cout<<"1";
else cout<<"2";
return 0;
}
F. Sasha and Interesting Fact from Graph Theory
题意:
共
n
n
n个结点,
n
−
1
n-1
n−1条边,边权为
[
1
,
m
]
[1,m]
[1,m],问
a
,
b
a,b
a,b之间的距离为
m
m
m的树能构建多少个。
题解:
枚举
a
,
b
a,b
a,b之间有多少条边,假设有
i
i
i条边,就有
i
−
1
i-1
i−1个点,选择
i
−
1
i-1
i−1个点的方案为
C
n
−
2
i
−
1
,
i
−
1
C_{n-2}^{i-1},i-1
Cn−2i−1,i−1个点随机排列的方案为
(
i
−
1
)
!
(i-1)!
(i−1)!。
i
i
i条边和为
m
m
m的方案为
C
m
−
1
i
−
1
C_{m-1}^{i-1}
Cm−1i−1,(隔板法)。剩下的边权可以随便选,方案数位
m
n
−
i
−
1
m^{n-i-1}
mn−i−1.
对于剩下的点,每个点都要加入到中间
(
i
+
1
)
(i+1)
(i+1)个点上,也就是
n
n
n个点要组成
(
i
+
1
)
(i+1)
(i+1)个森林。
根据广义 Cayley 定理:方案数为
(
i
+
1
)
∗
n
n
−
i
−
2
(i+1)*n^{n-i-2}
(i+1)∗nn−i−2
答案就是
∑
i
=
1
m
i
n
(
n
−
1
,
m
)
C
n
−
2
i
−
1
∗
(
i
−
1
)
!
C
m
−
1
i
−
1
∗
m
n
−
i
−
1
∗
(
i
+
1
)
∗
n
n
−
i
−
2
\sum_{i=1}^{min(n-1,m)}C_{n-2}^{i-1}*(i-1)!C_{m-1}^{i-1}*m^{n-i-1}*(i+1)*n^{n-i-2}
∑i=1min(n−1,m)Cn−2i−1∗(i−1)!Cm−1i−1∗mn−i−1∗(i+1)∗nn−i−2
广义 Cayley 定理:
n 个标号节点形成一个有 k 颗树的森林,使得给定的 k 个点没有两个点属于同一颗树的方案数为
k
⋅
n
n
−
k
−
1
.
k⋅n^{n−k−1}.
k⋅nn−k−1.
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>
#include <string>
#include <stack>
#include <cctype>
#include <vector>
#include <queue>
#include <set>
#include <utility>
#include <cassert>
#include <iomanip>
#include <deque>
#include <time.h>
#include <bitset>
using namespace std;
#define ll long long
#define maxn 1000005
#define mod 1000000007
#define MOD 998244353
#define Mod 1000000009
#define eps 1e-10
const ll inf=0x3f3f3f3f3f3f3f3f;
const ll INF=0x3f3f3f3f;
const ll mod1=1e9+7;
const ll mod2=1e9+9;
template <typename T>
inline void read(T& X) {X = 0; int w = 0; char ch = 0;while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();if (w) X = -X;}
char F[200];inline void write(int x){if(x == 0){putchar('0');return;}int tmp = x > 0 ? x : -x;int cnt = 0;if(x < 0)putchar( '-' );while(tmp > 0){F[cnt++] = tmp % 10 + '0';tmp /= 10;}while(cnt > 0)putchar(F[--cnt]) ;}
template<typename T> void print(T x){if(x>9) print(x/10);putchar(x%10+'0');}
ll q_pow(ll x,ll y,ll M){ll ans=1;while(y){if(y%2){y--;ans=ans*x%M;}else {y/=2;x=x*x%M;}}return ans;}
ll a[maxn],b[maxn];
void init(){
a[0]=1;
for(int i=1;i<maxn;i++)a[i]=a[i-1]*i%mod;
b[maxn-1]=q_pow(a[maxn-1],mod-2,mod);
for(int i=maxn-2;i>=0;i--)b[i]=b[i+1]*(i+1)%mod;
}
ll C(ll n,ll m){
return a[n]*b[m]%mod*b[n-m]%mod;
}
ll n,m,c,d;
ll solve(ll i){
if(i==n-1ll)return C(n-2,i-1)*a[i-1]%mod*C(m-1,i-1)%mod*q_pow(m,n-i-1ll,mod)%mod;
return C(n-2,i-1)*a[i-1]%mod*C(m-1,i-1)%mod*q_pow(m,n-i-1ll,mod)%mod*(i+1ll)%mod*q_pow(n,n-i-2,mod)%mod;
}
int main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
init();
cin>>n>>m>>c>>d;
ll ans=0;
for(ll i=1ll;i<=min(m,n-1ll);i++){
ans=(ans+solve(i))%mod;
}
cout<<ans;
return 0;
}