前言
这是一场很适合我的,可惜昨天由于在宿舍有点吵所以没打,今天来了一下,发现貌似如果打的话能上个几十分,感觉不懂啊,每次打的都是抽象场,唯独这次没打的场。然后就是,教育场真的很有教育意义,送分,送命是吧。
题解
:不懂啊,这个就很有教育意义,一眼读成了的感觉,然后第一发还交到上去了,难蚌。的话看样例不难发现,这个问题等价于我们可以将连续每段连续的看成个,然后求一下每个之间的的个数,求个和即可。
代码:
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define ll long long
#define lowbit(x) x&(-x)
#define x first
#define y second
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr);
#define two(x) __builtin_popcount(x)
using namespace std;
typedef pair<ll,ll> PII;
const int mod=998244353;
//ll qmi(ll a,ll b){ll res=1ll;while(b){if(b&1) res=res*a;b>>=1;a=(a)*(a);}return res;}
ll qmi(ll a,ll b,ll mod){ll res=1ll;while(b){if(b&1) res=(res%mod)*a%mod;b>>=1;a=(a%mod)*(a%mod)%mod;}return res%mod;}
//const int N=2001020;
//ll gcd(ll x,ll y){return y?gcd(y,x%y):x;} //最大公约数
//ll fact[N],infact[N];
//void c(ll mod){fact[0]=infact[0]=1;for(ll i=1;i<=N-5;i++){fact[i]=(i%mod*fact[i-1]%mod)%mod;infact[i]=(infact[i-1]%mod)*(qmi(i,mod-2,mod)%mod)%mod;}}
//ll C(ll a,ll b,ll mod){return ((fact[a]%mod*infact[b]%mod)%mod*(infact[a-b]%mod)%mod)%mod;}//组合数
const int N=100010;
int a[N];
void solve(){
int n;
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
int id=-1;
for(int i=1;i<=n;i++){
if(a[i]==1){
id=i;
break;
}
}
if(id==-1){
cout<<0<<"\n";
return;
}
int cnt0=0,ans=0;
for(int i=id;i<=n;i++){
if(a[i]==1){
ans+=cnt0;
cnt0=0;
}
else{
cnt0++;
}
}
cout<<ans<<"\n";
}
int main(){
//IOS
int t;
t=1;
cin>>t;
// f(N-2);
// for(int i=1;i<=cnt;i++){
// cout<<primes[i]<<" ";
// }
// c(mod);
while(t--) solve();
return 0;
}
:这个题感觉其难度要超过,其实是一个贪心的过程,我们不难发现,其实在数轴左侧的点上的怪等价于其绝对值上(也就是数轴右边)的怪,然后血量可以叠加,这是解决这个问题的重点(原因是我们的每秒发子弹可以自己定义射击谁),而且距离也一样,因此我们只需要依次考虑数轴右侧的怪物(按距离),用一个来记录我们每次杀死前一只怪物剩余的子弹量,以及当前怪物与前一只怪物的距离的子弹量是否的血量即可。时间复杂度。 代码:
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define ll long long
#define lowbit(x) x&(-x)
#define x first
#define y second
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr);
#define two(x) __builtin_popcount(x)
using namespace std;
typedef pair<ll,ll> PII;
const int mod=998244353;
//ll qmi(ll a,ll b){ll res=1ll;while(b){if(b&1) res=res*a;b>>=1;a=(a)*(a);}return res;}
ll qmi(ll a,ll b,ll mod){ll res=1ll;while(b){if(b&1) res=(res%mod)*a%mod;b>>=1;a=(a%mod)*(a%mod)%mod;}return res%mod;}
//const int N=2001020;
//ll gcd(ll x,ll y){return y?gcd(y,x%y):x;} //最大公约数
//ll fact[N],infact[N];
//void c(ll mod){fact[0]=infact[0]=1;for(ll i=1;i<=N-5;i++){fact[i]=(i%mod*fact[i-1]%mod)%mod;infact[i]=(infact[i-1]%mod)*(qmi(i,mod-2,mod)%mod)%mod;}}
//ll C(ll a,ll b,ll mod){return ((fact[a]%mod*infact[b]%mod)%mod*(infact[a-b]%mod)%mod)%mod;}//组合数
const int N=300010;
int a[N],k,n,x[N];
map<ll,ll> mp;
void solve(){
cin>>n>>k;
mp.clear();
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n;i++){
cin>>x[i];
mp[abs(x[i])]+=a[i];
}
vector<PII> v;
for(auto it:mp){
v.push_back({it.x,it.y});
}
// for(int i=0;i<v.size();i++){
//cout<<v[i].x<<" "<<v[i].y<<"\n";
// }
ll distance=0,ans=0;;
for(int i=0;i<v.size();i++){
//cout<<ans<<"\n";
if(ans+k*(v[i].x-distance)>=v[i].y){
ans=ans+k*(v[i].x-distance)-v[i].y;
distance=v[i].x;
}else{
cout<<"NO\n";
return;
}
}
cout<<"YES\n";
}
int main(){
//IOS
int t;
t=1;
cin>>t;
// f(N-2);
// for(int i=1;i<=cnt;i++){
// cout<<primes[i]<<" ";
// }
// c(mod);
while(t--) solve();
return 0;
}
:这个是个有点意思但又比较简单的思维题,开始想了很多种乱搞的方法,但是都被我一一掉,最后冷静下来想了下,发现这个题的难点在于所有数都要不一样但是和又要相等,就说明所有的数字都要在自身进行相应的加减操作(且操作之后这个数还要是正整数),于是我先想如果对序列进行排序,那么显然是可以的(当然并不是真排序,因为排序之后数字还都不变,那我们答案只要一一对应原来数字就行了),那么从贪心的角度来考虑,我们想要最大程度的满足条件二(每个数都不相等),我们一定是对每个数在自身进行加减操作,这样一定是最优,那么对于的每个数字,我们本身都可以进行加减的操作,唯独对于,我们无法进行减操作,那么我们可以让其他所有数都提供减操作之和,统计一下序列内所有的个数,那么就变成了判断是否,求可以用一个类似于的数组,求那自然就是前缀和了,时间复杂度。
代码:
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define ll long long
#define lowbit(x) x&(-x)
#define x first
#define y second
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr);
#define two(x) __builtin_popcount(x)
using namespace std;
typedef pair<ll,ll> PII;
const int mod=998244353;
//ll qmi(ll a,ll b){ll res=1ll;while(b){if(b&1) res=res*a;b>>=1;a=(a)*(a);}return res;}
ll qmi(ll a,ll b,ll mod){ll res=1ll;while(b){if(b&1) res=(res%mod)*a%mod;b>>=1;a=(a%mod)*(a%mod)%mod;}return res%mod;}
//const int N=2001020;
//ll gcd(ll x,ll y){return y?gcd(y,x%y):x;} //最大公约数
//ll fact[N],infact[N];
//void c(ll mod){fact[0]=infact[0]=1;for(ll i=1;i<=N-5;i++){fact[i]=(i%mod*fact[i-1]%mod)%mod;infact[i]=(infact[i-1]%mod)*(qmi(i,mod-2,mod)%mod)%mod;}}
//ll C(ll a,ll b,ll mod){return ((fact[a]%mod*infact[b]%mod)%mod*(infact[a-b]%mod)%mod)%mod;}//组合数
const int N=300010;
ll a[N],k,n,x[N],dp[N],q,s[N];
map<ll,ll> mp;
void solve(){
mp.clear();
cin>>n>>q;
for(int i=1;i<=n;i++){
cin>>a[i],dp[i]=0,s[i]=0;
}
dp[0]=0,s[0]=0;
for(int i=1;i<=n;i++){
s[i]=s[i-1]+a[i];
if(a[i]==1) dp[i]=dp[i-1]+1;
else dp[i]=dp[i-1];
}
for(int i=1;i<=q;i++){
int l,r;
cin>>l>>r;
int len=r-l+1;
if(len==1){
cout<<"NO\n";
}else{
ll cnt1=dp[r]-dp[l-1];
ll ans=s[r]-s[l-1]-len;
if(ans>=cnt1){
cout<<"YES\n";
}else cout<<"NO\n";
}
}
}
int main(){
//IOS
int t;
t=1;
cin>>t;
// f(N-2);
// for(int i=1;i<=cnt;i++){
// cout<<primes[i]<<" ";
// }
// c(mod);
while(t--) solve();
return 0;
}
:的话,开始不是特别会,然后听RegenFallen大佬讲了一半,就会了,然后就润去写了个很抽象的东西,在了一发之后过了。这个题其实是个怎么回事呢,是这么回事,我们经过模拟不难发现我们要解决以下问题:
- 什么样的史莱姆不可以被吃掉?
- 在能被吃掉的情况下,怎么求最小的步骤?
对于问题我开始的想法也是非常的朴素,一样就可以发现如果最大的那个史莱姆不小于所有的其他的和,那么这个一定不会被吃掉,但是这个情况并不是很全面,如果所有的数都相等,那么我们必然一个都不会被吃掉,再仔细观察和模拟样例,我们可以发现这样一个事情:对于从~的所有史莱姆,大小为,他们如果能被吃掉,必然有两种大情况:
- 左边有一个史莱姆在左边不停扩充(如果本身大也可以不扩充)至比大。
- 右边有一个史莱姆在右边不停扩充(如果本身大也可以不扩充)至比大。
只有情况,只有情况然后如果左右都没有这样的史莱姆,那么它必然不可能被吃掉。
但是问题又来了,左右两边的史莱姆怎么扩充呢,他们的扩充过程肯定也是符合以上两种情况的,那么如果这么考虑的话,情况就非常非常多,肯定是不利于解题的。因此我们可以考虑这么单一的情况,就拿左边来举例吧,在左边我们选定一个区间,左端点可以变化,但是右端点一定是(因为要扩充到),对于这么一个区间,我们不难发现这个区间只要不是所有数都相同,那么一定存在一种吞并(哇,这个词真好)方式,使得最后合并成一个大小为的史莱姆,而且操作必然是区间长度,但是如果区间所有数都想等,那么我们必然没有办法操作,因此核心问题解决了,我们可以用来判断区间是否所有数都相等,再对每个史莱姆进行两次二分搜索求解最优的合并步骤(单个),注意和要特判,总时间复杂度。
代码
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define ll long long
#define lowbit(x) x&(-x)
#define x first
#define y second
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr);
#define two(x) __builtin_popcount(x)
using namespace std;
typedef pair<ll,ll> PII;
const int mod=998244353;
//ll qmi(ll a,ll b){ll res=1ll;while(b){if(b&1) res=res*a;b>>=1;a=(a)*(a);}return res;}
ll qmi(ll a,ll b,ll mod){ll res=1ll;while(b){if(b&1) res=(res%mod)*a%mod;b>>=1;a=(a%mod)*(a%mod)%mod;}return res%mod;}
//const int N=2001020;
//ll gcd(ll x,ll y){return y?gcd(y,x%y):x;} //最大公约数
//ll fact[N],infact[N];
//void c(ll mod){fact[0]=infact[0]=1;for(ll i=1;i<=N-5;i++){fact[i]=(i%mod*fact[i-1]%mod)%mod;infact[i]=(infact[i-1]%mod)*(qmi(i,mod-2,mod)%mod)%mod;}}
//ll C(ll a,ll b,ll mod){return ((fact[a]%mod*infact[b]%mod)%mod*(infact[a-b]%mod)%mod)%mod;}//组合数
const int N=300010;
int n;
ll a[N],ans[N],dp[N],s[N];
bool check1(int x,int id){//id大 x小
if(s[id-1]-s[x-1]>a[id] && dp[id-1]!=dp[x]) return true;
return false;
}
bool check2(int x,int id){ //id大 x小
if(s[id]-s[x]>a[x] && dp[id]!=dp[x+1]) return true;
return false;
}
void solve(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i],s[i]=0,dp[i]=0,ans[i]=1e18;
if(n==1){
cout<<"-1\n";
return;
}
for(int i=1;i<=n;i++){
if(i==1){
if(a[i+1]>a[i]) ans[i]=1;
}else if(i==n){
if(a[i-1]>a[i]) ans[i]=1;
}else if(a[i-1]>a[i] || a[i+1]>a[i]){
ans[i]=1;
}
}
dp[0]=s[0]=0;
for(int i=1;i<=n;i++){
if(a[i]!=a[i-1]){
dp[i]=dp[i-1]+1;
}else dp[i]=dp[i-1];
s[i]=s[i-1]+a[i];
}
for(ll i=1;i<=n;i++){
if(ans[i]==1) continue;
ll l=1,r=i-1;
bool ok=false;
if(i>1){
while(l<r){
ll mid=l+r+1>>1;
if(check1(mid,i)) l=mid,ok=true;
else r=mid-1;
}
if(check1(l,i)) ans[i]=min(ans[i],i-l);
}
if(i<n){
l=i+1,r=n;
while(l<r){
int mid=l+r>>1;
if(check2(i,mid)) r=mid,ok=true;
else l=mid+1;
}
if(check2(i,l)) ans[i]=min(ans[i],l-i);
}
if(ans[i]==1e18) ans[i]=-1;
}
for(int i=1;i<=n;i++){
cout<<ans[i]<<" ";
}
cout<<"\n";
}
int main(){
IOS
int t;
t=1;
cin>>t;
while(t--) solve();
return 0;
}
感悟
真不错!