ARC 179 & Codeforces Round 955 (Div. 2, with prizes from NEAR!)
ARC
A
这道题我还不会证明哎。
可以猜想,序列要么是正着排要么是倒着排的。如果都不可以的就输出 No
。具体来说,
证明,待补。
B
看到
时间复杂度
C
先说一个错误的做法。
很容易想到,第一次一定要先排一个序,否则比较难搞。排完序我们首尾配对一直到中间,配成
为什么是错的呢?考虑一个例子:
但是我们发现如果只是首尾配对,不配对其他的,一定是可行的。因为:如果都是正数,很显然;如果一个负一个正,加起来一定不超过绝对值的最大值。我们配对以后直接二分插入的位置就可以了。
关于排序有一个 stl 的技巧:stable_sort(id+1,id+1+n,cmp);
,其中 cmp
函数中询问。
CF
A
显然,Yes
。
B
我写的是一个玄学复杂度的!就是,我们可以在
时间复杂度可以感性理解为
Code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin>>t;
while (t--){
ll x,y,k,f=0;
cin>>x>>y>>k;
while (k>0 && x>=y){
ll m=x/y;
m++;
m*=y;
ll t=m-x;
if (t>k){
cout<<x+k<<"\n";
f=1;
break;
}
else{
x+=t;
k-=t;
while (x%y==0){
x/=y;
}
}
}
if (f){
continue;
}
if (k==0){
cout<<x<<"\n";
continue;
}
ll t=y-x;
if (t>k){
cout<<x+k<<"\n";
}
else{
k-=t,x=1;
ll m=y-1;
ll r=k%m;
cout<<x+r<<"\n";
}
}
return 0;
}
C
很显然的 dp。设
Code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 1e5+5;
ll n,L,R,a[N],s[N],dp[N];
ll fl(int p){
int l=-1,r=p;
while (l+1<r){
int mid=l+r>>1;
if (s[p]-s[mid]<=R){
r=mid;
}
else{
l=mid;
}
}
return r;
}
ll fr(int p){
int l=-1,r=p;
while (l+1<r){
int mid=l+r>>1;
if (s[p]-s[mid]>=L){
l=mid;
}
else{
r=mid;
}
}
return l;
}
void solve(){
cin>>n>>L>>R;
for (int i=1; i<=n; i++){
dp[i]=0;
cin>>a[i];
s[i]=s[i-1]+a[i];
}
int pl=-1,pr=-1;
dp[0]=0;
multiset<ll> st;
for (int i=1; i<=n; i++){
int lb=fl(i),rb=fr(i);
if (lb<=rb){
while (pr<rb){
pr++;
st.insert(-dp[pr]);
}
while (pl+1<lb){
pl++;
st.erase(st.find(-dp[pl]));
}
}
if (st.size()){
dp[i]=-(*st.begin())+1;
}
dp[i]=max(dp[i],dp[i-1]);
}
cout<<dp[n]<<"\n";
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin>>t;
while (t--){
solve();
}
return 0;
}
D
我们可以用二维前缀和求出每一个
时间复杂度
Code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 5e2+2;
ll n,m,k,a[N][N],c[N][N];
string s[N];
ll cal(int x1,int y1,int x2,int y2){
return c[x2][y2]-c[x1-1][y2]-c[x2][y1-1]+c[x1-1][y1-1];
}
ll cal1(int x1,int y1,int x2,int y2){
return a[x2][y2]-a[x1-1][y2]-a[x2][y1-1]+a[x1-1][y1-1];
}
void solve(){
cin>>n>>m>>k;
for (int i=1; i<=n; i++){
for (int j=1; j<=m; j++){
cin>>a[i][j];
}
}
for (int i=1; i<=n; i++){
cin>>s[i];
s[i]=" "+s[i];
for (int j=1; j<=m; j++){
if (s[i][j]=='0'){
c[i][j]=-1;
a[i][j]*=-1;
}
else{
c[i][j]=1;
}
}
}
for (int i=1; i<=n; i++){
for (int j=1; j<=m; j++){
c[i][j]+=c[i-1][j]+c[i][j-1]-c[i-1][j-1];
a[i][j]+=a[i-1][j]+a[i][j-1]-a[i-1][j-1];
}
}
ll g=0;
for (int i=1; i+k-1<=n; i++){
for (int j=1; j+k-1<=m; j++){
ll sum=cal(i,j,i+k-1,j+k-1);
sum=abs(sum);
g=__gcd(g,sum);
}
}
ll sum=cal1(1,1,n,m);
if ((g==0 && sum==0) || (g!=0 && sum%g==0)){
cout<<"YES\n";
}
else{
cout<<"NO\n";
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin>>t;
while (t--){
solve();
}
return 0;
}
E
有妙妙解法。
设
问题是怎么算。除了内部的,还有一个端点在左边一个端点在右边的。官方题解是维护了三个值,很复杂。有没有直接算的方法?
我们发现,如果
直接记忆化搜索即可,复杂度是
Code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll mod = 1e9+7;
map<pair<ll,ll>,ll> mp;
ll sol(ll n,ll k){
if (k==0 || n==1){
return 1;
}
if (mp.count({n,k})){
return mp[{n,k}];
}
ll c=0;
while ((1ll<<c+1)<n){
c++;
}
ll l=sol(1ll<<c,k),r=sol(n-(1ll<<c),k-1);
ll ans=l+r;
if (c<=k){
ll s=min((1ll<<k)-1,n-(1ll<<c));
ans+=s%mod*((1ll<<c)%mod)%mod;
}
mp[{n,k}]=ans%mod;
return ans%mod;
}
void solve(){
ll n,k;
cin>>n>>k;
cout<<sol(n,k)<<"\n";
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin>>t;
while (t--){
solve();
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧