A. Game
题意:
你只能跳一次,可以从1的地方跳到任意1的地方,消耗的值为距离差,问最小消耗多少。
题解:
从前面最后的1跳到后面最前的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 400005
#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 a[111];
void solve(){
int n;
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
int index1,index2;
for(int i=1;i<=n;i++){
if(a[i]==0)break;
index1=i;
}
for(int i=n;i>=1;i--){
if(a[i]==0)break;
index2=i;
}
cout<<max(0,index2-index1)<<"\n";
}
int main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int t;
cin>>t;
while(t--){
solve();
}
return 0;
}
B. Game of Ball Passing
题意:
有n个人踢球,每人个传球次数为
a
i
a_i
ai,问最少需要几个球。
题解:
先考虑最大值很大的情况下,最大的人和吗,每个人都传一次球,还剩多少次传球就还需要多少球,若没剩下只需要1个球,若没人踢球答案为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 400005
#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 a[maxn];
void solve(){
int n;
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
ll sum=0;
sort(a+1,a+1+n);
for(int i=1;i<=n;i++){
sum+=a[i];
}
sum-=a[n];
if(a[n]==0)cout<<"0\n";
else if(sum<a[n])cout<<a[n]-sum<<"\n";
else cout<<1<<"\n";
}
int main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int t;
cin>>t;
while(t--){
solve();
}
return 0;
}
C. Weird Sum
题意:
问所有相同的值的哈夫曼距离总和。
题解:
把x,和y分别计算。因为每两两之间都会计算一次所以分开考虑不影响结果。分别对x,y排序后计算每一段会被计算几次就可以O(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 400005
#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;}
vector<int>h[111111],l[111111];
int main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int n,m,x;
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>x;
h[x].push_back(i);
l[x].push_back(j);
}
}
for(int i=1;i<=100000;i++)sort(h[i].begin(),h[i].end()),sort(l[i].begin(),l[i].end());
ll ans=0;
for(int i=1;i<=100000;i++){
if(h[i].size()==0)continue;
ll sumh=0,suml=0;
for(int j=0;j<h[i].size();j++){
sumh+=h[i][j];
suml+=l[i][j];
}
for(int j=1;j<h[i].size();j++){
sumh-=h[i][j-1];
suml-=l[i][j-1];
ans=(ll)ans+sumh-(ll)h[i][j-1]*(ll)(h[i].size()-j)+suml-(ll)l[i][j-1]*(ll)(h[i].size()-j);
}
}
cout<<ans;
return 0;
}
D. Integral Array
题意:
对于一个数组,
对
于
任
意
数
组
中
的
x
,
y
,
有
y
x
(
向
下
取
整
,
y
>
=
x
)
在
数
组
中
对于任意数组中的x,y,有\frac{y}{x}(向下取整,y>=x)在数组中
对于任意数组中的x,y,有xy(向下取整,y>=x)在数组中。问每个数组是否符合这个条件。
题解:
若枚举除数,时间为
n
n
n\sqrt{n}
nn,会超时。观察到这题有一个上界,上界很小,可以离散化,对于每个数
y
y
y来说,若前面不存在
x
x
x,则后面
[
x
∗
y
,
x
∗
y
+
x
)
[x*y,x*y+x)
[x∗y,x∗y+x)必须没有值。这个可以通过前缀和O(1)判断。
对于每个
x
x
x只会计算
n
x
\frac{n}{x}
xn次。
时间复杂度是一个调和级数O(nlogn)
#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 400005
#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 vis[1111111];
vector<int>a;
int sum[1111111];
int main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int t;
cin>>t;
while(t--){
int n,c;
cin>>n>>c;
a.clear();
for(int i=1;i<=c;i++)vis[i]=0;
for(int i=1,x;i<=n;i++)cin>>x,a.push_back(x),vis[x]=1;
sort(a.begin(),a.end());
if(a[0]!=1){
cout<<"No\n";
continue;
}
for(int i=1;i<=a[n-1];i++){
sum[i]=sum[i-1]+vis[i];
}
a.erase(unique(a.begin(),a.end()),a.end());
n=a.size();
int f=1;
for(int i=1;i<n;i++){
for(int j=2;j*a[i]<=a[n-1];j++){
int r=min(a[n-1],j*a[i]+a[i]-1),l=j*a[i];
if(!vis[j]&&sum[r]-sum[l-1]>0){
f=0;
break;
}
}
}
if(f)cout<<"Yes\n";
else cout<<"No\n";
}
return 0;
}
E. Tyler and Strings
题意:
你有一个S和T字符串,问S字符串排列组合有多少种方案是字典序小于T的。
题解:
枚举当前前
i
−
1
i-1
i−1位字符S和T相同,那么下一位小于T的数
n
u
m
=
∑
i
=
0
T
[
i
]
−
1
c
n
t
[
i
]
num=\sum_{i=0}^{T[i]-1}cnt[i]
num=∑i=0T[i]−1cnt[i],剩下的
n
−
i
n-i
n−i位就可以随便排序。方案数位
n
u
m
∗
(
n
−
i
)
!
c
n
t
[
0
]
!
c
n
t
[
1
]
!
.
.
.
c
n
t
[
N
]
!
num*\frac{(n-i)!}{cnt[0]!cnt[1]!...cnt[N]!}
num∗cnt[0]!cnt[1]!...cnt[N]!(n−i)!,然后对于下一步来说,当前用掉一个T[i],cnt[t[i]]要减1.对于带修改的查询区间和,可以用线段树或树状数组维护。最后还需要判断一下,S是否是T的前缀,因为这样S全取也是一种方案,这种方案是因为数量少产生的,而我们计算的方案是字典序严格小的方案。最后答案+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 200005
#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];
ll tree[maxn<<2],cnt[maxn];
ll s[maxn],t[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;
}
void update(int id,int l,int r,int pos,ll x){
if(l==r){
tree[id]+=x;
return;
}
int mid=(l+r)>>1;
if(mid>=pos)update(id<<1,l,mid,pos,x);
else update(id<<1|1,mid+1,r,pos,x);
tree[id]=tree[id<<1]+tree[id<<1|1];
}
ll query(int id,int l,int r,int lx,int ly){
if(l>=lx&&r<=ly)return tree[id];
int mid=(l+r)>>1;
ll ans=0;
if(mid>=lx)ans+=query(id<<1,l,mid,lx,ly);
if(mid<ly)ans+=query(id<<1|1,mid+1,r,lx,ly);
return ans;
}
int main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
init();
ll n,m;
cin>>n>>m;
for(int i=0;i<n;i++)cin>>s[i];
for(int i=0;i<m;i++)cin>>t[i];
for(int i=0;i<n;i++){
cnt[s[i]]++;
update(1,0,maxn-1,s[i],1);
}
ll inv=1;
for(int i=0;i<maxn;i++)inv=inv*b[cnt[i]]%MOD;
int f=0;
ll ans=0;
for(int i=0;i<min(n,m);i++){
ll num=query(1,0,maxn-1,0,t[i]-1);
ans=(ans+num*a[n-i-1]%MOD*inv%MOD)%MOD;
if(cnt[t[i]]){
inv=inv*a[cnt[t[i]]]%MOD;
cnt[t[i]]--;
inv=inv*b[cnt[t[i]]]%MOD;
update(1,0,maxn-1,t[i],-1);
}
else{
f=1;
break;
}
}
if(!f&&n<m)ans=(ans+1)%MOD;
cout<<ans;
return 0;
}
F. Serious Business
题意:
一共有三层楼,只能往右走或往下走,到那
(
i
,
j
)
(i,j)
(i,j)位置可以获得
a
i
,
j
a_{i,j}
ai,j的贡献,第二层不能走,除非第二层有优惠存在,那一段可以走,贡献要减去优惠。问走到
(
3
,
n
)
(3,n)
(3,n)的最大贡献。
题解:
分解成两块,一块为从
(
1
,
1
)
−
>
(
2
,
i
)
(1,1)->(2,i)
(1,1)−>(2,i)的贡献,以及从
(
2
,
i
)
−
>
(
3
,
n
)
(2,i)->(3,n)
(2,i)−>(3,n)的贡献。
p
r
e
f
[
k
]
[
i
]
pref[k][i]
pref[k][i]代表第k层到i位置的贡献。
s
[
i
]
=
p
r
e
f
[
1
]
[
i
]
−
p
r
e
f
[
2
]
[
i
−
1
]
s[i]=pref[1][i]−pref[2][i-1]
s[i]=pref[1][i]−pref[2][i−1]代表从i位置下第二层
f
[
i
]
=
p
r
e
f
[
2
]
[
i
]
−
p
r
e
f
[
3
]
[
i
−
1
]
+
p
r
e
f
[
3
]
[
n
]
f[i]=pref[2][i]−pref[3][i-1]+pref[3][n]
f[i]=pref[2][i]−pref[3][i−1]+pref[3][n]从i位置下第三层
对于一段
[
l
,
r
]
,
优
惠
为
w
[l,r],优惠为w
[l,r],优惠为w的段,可以选择从i下第二层,从j下第三层,
l
<
=
i
<
=
j
<
=
r
l<=i<=j<=r
l<=i<=j<=r。用线段树维护。枚举每一个右端点。对于这一段来说,可以用下第一层的最大代价-w来更新r+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 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;}
struct node{
ll x,y,z;
}tree[maxn<<2];
ll s[maxn],t[maxn],sum[4][maxn];
ll a[4][maxn];
vector<pair<ll,ll> >g[maxn];
void pushup(int id){
tree[id].x=max(tree[id<<1].x,tree[id<<1|1].x);
tree[id].y=max(tree[id<<1].y,tree[id<<1|1].y);
tree[id].z=max({tree[id<<1].z,tree[id<<1|1].z,tree[id<<1].x+tree[id<<1|1].y});
return ;
}
void build(int id,int l,int r){
if(l==r){
tree[id].x=s[l];
tree[id].y=t[l];
tree[id].z=s[l]+t[l];
return;
}
int mid=(l+r)>>1;
build(id<<1,l,mid);
build(id<<1|1,mid+1,r);
pushup(id);
}
void update(int id,int l,int r,int pos,ll val){
if(l==r){
tree[id].x=max(tree[id].x,val);
tree[id].z=max(tree[id].z,tree[id].x+tree[id].y);
return;
}
int mid=(l+r)>>1;
if(mid>=pos)update(id<<1,l,mid,pos,val);
else update(id<<1|1,mid+1,r,pos,val);
pushup(id);
}
node query(int id,int l,int r,int lx,int ly){
if(l>=lx&&r<=ly)return tree[id];
int mid=(l+r)>>1;
node ans,ans1,ans2;
int f1=0,f2=0;
if(mid>=lx)ans1=query(id<<1,l,mid,lx,ly),f1=1;
if(mid<ly)ans2=query(id<<1|1,mid+1,r,lx,ly),f2=1;
if(f1&&f2){
ans.x=max(ans1.x,ans2.x);
ans.y=max(ans1.y,ans2.y);
ans.z=max({ans1.z,ans2.z,ans1.x+ans2.y});
return ans;
}
if(f1)return ans1;
if(f2)return ans2;
}
int main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
ll n,q;
cin>>n>>q;
for(int i=1;i<=3;i++){
for(int j=1;j<=n;j++){
cin>>a[i][j];
sum[i][j]=sum[i][j-1]+a[i][j];
}
}
for(int i=1;i<=n;i++)s[i]=sum[1][i]-sum[2][i-1],t[i]=sum[2][i]-sum[3][i-1]+sum[3][n];
for(ll i=1,l,r,w;i<=q;i++){
cin>>l>>r>>w;
g[r].push_back(make_pair(l,w));
}
build(1,1,n);
ll ans=-inf;
for(int i=1;i<=n;i++){
for(auto &it:g[i]){
ll l=it.first,w=it.second;
node res=query(1,1,n,l,i);
ans=max(ans,res.z-w);
if(i<n)update(1,1,n,i+1,res.x-w);
}
}
cout<<ans;
return 0;
}