A:Onewan的疑惑
题意:找有多少小于等于n的x满足x+(19260817)≥n−(114514)。
移项可得x的下界,注意x最大得有1。
#include<bits/stdc++.h> #define ll long long #define Int __int128 #define pb push_back #define eb emplace_back #define MAX_LOG 21 #define ff first #define ss second #define M 5005 #define RI register int #define CI const int& #define ull unsigned long long using namespace std; const int INF=0x3f3f3f3f; typedef pair<ll,ll> PLL; typedef pair<int,int>PII; ll gcd(ll a,ll b) { if(b) while((a%=b)&&(b%=a)); return a+b; }//最大公约数函数 ll spid(ll a,ll b,ull p) { ll ans=1; while(b) { if(b&1)ans=(Int)ans*a%p; b>>=1; a=(Int)a*a%p; } return ans; }//快速幂函数 ///泡沫在阳光下闪烁,像星辰在寂静得夜空中闪耀 ///秋雨 const ll N=5e3+10; void solve() { ll n;cin>>n; ll l=max(n-114514-19260817,1ll); ll r=n; ll ans=max(r-l+1,0ll); cout<<ans<<'\n'; } signed main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); int t=1; // cin>>t; while(t--) { solve(); } } ///在秋天邂逅, 在春天发芽,在夏天壮大,在秋天萧瑟,在冬天萎缩, ///而后,春天再度归来。
B:菲菲姐的游戏:
题意:把数组分成两个连续的子数组,你可以在左边选至多k1个数,另一个人可以在右边至多选k2个数,你的值是选的数的平均数,她的值是选的数的
中位数,问有没有一种分数组的方法使得你可以大于她。
思考两个人在某个数组里的最佳取数法
你需要取一段区间,使得平均值最大,那么思考发现,你肯定会贪心的优先选择数字大的元素,很容易发现选择唯一最大的那个数字便是你能在某个区间内能得到平均值最大的选数方案
同理,菲菲姐也是选择一个最大的数便是最大的选取中位数的方案。
由于数组是分成左右两个区间,那么我们只需要记录左右两个区间中的最大值便可,
开两个数组,一个maxa维护1~i的区间最大值,类似于前缀和,再开一个数组维护i~n的区间最大值即可
vector<ll>maxa(a.begin(),a.end()); vector<ll>rmaxa(a.begin(),a.end()); for(int i=2;i<=n;i++)maxa[i]=max(maxa[i],maxa[i-1]); for(int i=n-1;i>=1;i--)rmaxa[i]=max(rmaxa[i],rmaxa[i+1]);
答案便是枚举分割点
bool ans=0; for(int i=1;i<=n;i++) if(maxa[i]>rmaxa[i])ans=1;///如果左区间的最大值大于右区间,说明在这个点分开便是必胜 if(ans)cout<<"Yes\n"; else cout<<"No\n";
完整代码:
#include<bits/stdc++.h> #define ll long long #define Int __int128 #define pb push_back #define eb emplace_back #define MAX_LOG 21 #define ff first #define ss second #define M 5005 #define RI register int #define CI const int& #define ull unsigned long long using namespace std; const int INF=0x3f3f3f3f; typedef pair<ll,ll> PLL; typedef pair<int,int>PII; ll gcd(ll a,ll b) { if(b) while((a%=b)&&(b%=a)); return a+b; }//最大公约数函数 ll spid(ll a,ll b,ull p) { ll ans=1; while(b) { if(b&1)ans=(Int)ans*a%p; b>>=1; a=(Int)a*a%p; } return ans; }//快速幂函数 ///泡沫在阳光下闪烁,像星辰在寂静得夜空中闪耀 ///秋雨 const ll N=5e3+10; void solve() { ll n,k1,k2; cin>>n>>k1>>k2; vector<ll>a(n+1); for(int i=1;i<=n;i++)cin>>a[i]; vector<ll>maxa(a.begin(),a.end()); vector<ll>rmaxa(a.begin(),a.end()); for(int i=2;i<=n;i++)maxa[i]=max(maxa[i],maxa[i-1]); for(int i=n-1;i>=1;i--)rmaxa[i]=max(rmaxa[i],rmaxa[i+1]); bool ans=0; for(int i=1;i<=n;i++) { if(maxa[i]>rmaxa[i])ans=1; } if(ans)cout<<"Yes\n"; else cout<<"No\n"; } signed main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); int t=1; // cin>>t; while(t--) { solve(); } } ///在秋天邂逅, 在春天发芽,在夏天壮大,在秋天萧瑟,在冬天萎缩, ///而后,春天再度归来。
C:猪猪养成计划1:
题意:n个点,q次操作,会让你从l挨个遍历到r,之前遍历过的不会在遍历;或者问你第i个是第几个被遍历的。
根据题意会发现主要的时间复杂度集中在区间存在重复遍历的情况,那么只要保证区间不会被重复遍历到即可,那么只需要在遍历的时候,把遍历过的点打上跳跃标记即可,例如区间l~r的所有元素全部标记成r,那么在遍历时会发现遇到其中任何一个元素,都可以直接跳过这个已经遍历过的区间,从而达到时间要求。
#include<bits/stdc++.h> #define ll long long #define Int __int128 #define pb push_back #define eb emplace_back #define MAX_LOG 21 #define ff first #define ss second #define M 5005 #define RI register int #define CI const int& #define ull unsigned long long using namespace std; const int INF=0x3f3f3f3f; typedef pair<ll,ll> PLL; typedef pair<int,int>PII; ll gcd(ll a,ll b) { if(b) while((a%=b)&&(b%=a)); return a+b; }//最大公约数函数 ll spid(ll a,ll b,ull p) { ll ans=1; while(b) { if(b&1)ans=(Int)ans*a%p; b>>=1; a=(Int)a*a%p; } return ans; }//快速幂函数 ///泡沫在阳光下闪烁,像星辰在寂静得夜空中闪耀 ///秋雨 const ll N=5e3+10; void solve() { ll n,q;cin>>n>>q; vector<ll>go(n+1,0); vector<ll>ans(n+1,0);///初始没访问过,答案全为0 ll cnt=1;///遍历编号变量 while(q--) { ll op;cin>>op; if(op==1) { ll l,r;cin>>l>>r; for(int i=l;i<=r;i++) { if(!ans[i])ans[i]=cnt++;///没标记过则打上答案 if(go[i]!=0)i=go[i]; else go[i]=r;///打上跃迁标记 } go[l]=r; }else { ll x;cin>>x; cout<<ans[x]<<'\n'; } } } signed main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); int t=1; // cin>>t; while(t--) { solve(); } } ///在秋天邂逅, 在春天发芽,在夏天壮大,在秋天萧瑟,在冬天萎缩, ///而后,春天再度归来。
D:猪猪养成计划2
题意:有n个猪,每个猪你和他玩耍会花费b_i,否则花费v_i,每个猪需要玩耍的时间段是[a_i,a_i+m−1],你每个时刻只能陪一头猪。问最小花费。
有两种思考方向,第一种是默认陪伴所有猪,再根据具体情况去送礼物不陪伴某些猪来使得陪伴猪猪的时间不产生交集
第二种是默认不陪伴所有猪,再去思考可以去陪伴哪些猪来减小花费
很明显第一种情况过于繁琐,无法轻易解决问题
考虑到数据范围,会发现第二种可以通过更新(动态规划)来解决该问题
思考,当我们以第i天为起始点选择某个猪猪来减少花费时,我们会选择b-value值最小的猪猪,也就是value-b最大的猪猪,并且只能选择一只猪猪,接下来选择猪猪后,i~i+m-1这个区间不可选择其他猪猪(因为会冲突),所以我们开一个dp数组来更新答案,我们需要减少花费来使得答案最小化,当我们将value-b(增加的减少花费)取相反数时,就变成了希望减少的花费最大化,也就是我们需要dp数组最后能最大。
根据上述理论可以开辟一个dp数组,dp[i]表示1~i天选择合适的猪猪方案后的减少的最大花费,很明显第i+1天也可以运用第i天的方案,所以有dp[i]=max(dp[i],dp[i-1]);
,根据上述选择猪猪的情况,可以得到dp[i+m]=max(dp[i]+max(最优猪猪减少的花费),dp[i+m]);
可以发现根据这两个递推式便可以更新出第n天后,也就是第n+1天减小的最大花费是多少。
最优猪猪只能有一个,所以只需要维护最优的猪猪的减少的花费即可,即维护1~i每个点的value-b的最大值即可
那么需要计算出不陪伴所有猪猪的总花费,减去最大减少的花费即可
完整代码:
#include<bits/stdc++.h> #define ll long long #define Int __int128 #define pb push_back #define eb emplace_back #define MAX_LOG 21 #define ff first #define ss second #define M 5005 #define RI register int #define CI const int& #define ull unsigned long long using namespace std; const int INF=0x3f3f3f3f; typedef pair<ll,ll> PLL; typedef pair<int,int>PII; ll gcd(ll a,ll b) { if(b) while((a%=b)&&(b%=a)); return a+b; }//最大公约数函数 ll spid(ll a,ll b,ull p) { ll ans=1; while(b) { if(b&1)ans=(Int)ans*a%p; b>>=1; a=(Int)a*a%p; } return ans; }//快速幂函数 ///泡沫在阳光下闪烁,像星辰在寂静得夜空中闪耀 ///秋雨 const ll N=1e5+10; ll a[N]; ll dp[N]; ll b[N]; ll sum[N]; void solve() { ll n,m;cin>>n>>m; for(int i=1;i<=n;i++)cin>>a[i]; ll all=0;///不陪伴所有猪猪的总花费 for(int i=1;i<=n;i++) { ll u,v;cin>>u>>v; b[i]=v-u;///value-b all+=v;///不陪伴所有猪猪的总花费求和过程 sum[a[i]]=max(sum[a[i]],b[i]);///每个点的最优猪猪的减少的花费 } for(int i=1;i<=n+1;i++) { dp[i]=max(dp[i],dp[i-1]); if(sum[i])dp[i+m]=max(dp[i+m],dp[i]+sum[i]);///递推式 } cout<<all-dp[n+1]<<'\n';///总花费减去n+1天陪伴猪猪减少的花费便是答案 } signed main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); int t=1; // cin>>t; while(t--) { solve(); } } ///在秋天邂逅, 在春天发芽,在夏天壮大,在秋天萧瑟,在冬天萎缩, ///而后,春天再度归来。
E:min25筛:
题意:给你一个数组,f_{ij}定义为\prod_{k=i}^jk=a_k一直除25直到没有25这个因子。 求\sum_{i=1}^n\sum_{j=1}^nf_{ij}。
首先我们要了解怎么计算怎么一次性计算正常区间内所有子区间的乘积和,通过思考后会发现递推式cnt=cnt*a_i+a_i
我们可以这么用
定义一个变量cnt=0
遍历区间,这时候遇到第一个值,cnt=a_1
第二个 cnt=a_1*a_2+a_2
第三个cnt=a_1*a_2*a_3+a_2*a_3+a_3
....
会发现将上面的每次遍历到的cnt求和便是正常区间内所有子区间的乘积和。
那么本题的特殊性便是存在25需要除掉的处理,那么我们可以考虑将cnt分成两部分,一部分存带因子5的,一部分存不带因子5的,分别表示为cnt[0],cnt[1]。
那么上面的递推式子便可以转化为两种情况:
若遇到的a[i]存在因子5,那么ans=(ans+cnt[0]*a[i]%mod+cnt[1]*a[i]%mod*inv%mod+a[i])%mod;
反之:ans=(ans+cnt[0]*a[i]%mod+cnt[1]*a[i]%mod+a[i])%mod;
可以清楚的认识到ans本身就是求和的意思。
再思考如何维护一下cnt[0]和cnt[1]本身的意义即可
完整代码:
#include<bits/stdc++.h> #define ll long long #define Int __int128 #define pb push_back #define eb emplace_back #define MAX_LOG 21 #define ff first #define ss second #define M 5005 #define RI register int #define CI const int& #define ull unsigned long long using namespace std; const int INF=0x3f3f3f3f; typedef pair<ll,ll> PLL; typedef pair<int,int>PII; ll gcd(ll a,ll b) { if(b) while((a%=b)&&(b%=a)); return a+b; }//最大公约数函数 ll spid(ll a,ll b,ull p) { ll ans=1; while(b) { if(b&1)ans=(Int)ans*a%p; b>>=1; a=(Int)a*a%p; } return ans; }//快速幂函数 ///泡沫在阳光下闪烁,像星辰在寂静得夜空中闪耀 ///秋雨 const ll N=1e5+10; ll cnt[3]; ll a[N]; ll mod=1e9+7; ll get_inv(ll x) { return spid(x,mod-2,mod); } void solve() { ll n; cin>>n; ll ans=0; ll inv=get_inv(25); for(int i=1;i<=n;i++) { cin>>a[i]; while(a[i]%25==0) a[i]/=25; } for(int i=1;i<=n;i++) { if(a[i]%5==0)///如果带5 { ans=(ans+cnt[0]*a[i]%mod+cnt[1]*a[i]%mod*inv%mod+a[i])%mod;///因子5的前缀乘 ll p0=cnt[1]*a[i]%mod*inv%mod;///带五的变成不带5 cnt[1]=(cnt[0]*a[i]%mod+a[i])%mod;///不带5的变成带5的 cnt[0]=p0;///交换 } else { ans=(ans+cnt[0]*a[i]%mod+cnt[1]*a[i]%mod+a[i])%mod; cnt[0]=(cnt[0]*a[i]+a[i])%mod; cnt[1]=cnt[1]*a[i]%mod; } } cout<<ans<<"\n"; } signed main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); int t=1; // cin>>t; while(t--) { solve(); } } ///在秋天邂逅, 在春天发芽,在夏天壮大,在秋天萧瑟,在冬天萎缩, ///而后,春天再度归来。