思路:
不清楚具体什么做法。随便把式子拆解了一下是下面这个样子
$x=\frac {1}{a}$ $(n-b*y)$
很显然式子有两种解法:
1.n-by=0.代表n是b的倍数:因为y应该要是一个整数.此时可以构造n-b*(n/b)可得x为0
2.当无法构造这种情况的时候。说明x是一个>=1的数
此时先解$y$进而解出$x$。$y=\frac{(n-k*a)}b$,从小到达枚举是否存在合适的k能解出y此时带入原来的式子即$x=k$就可以了
AC Code:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>PII;
typedef unsigned long long ull;
const int M=2010;
const ll llINF=0x3f3f3f3f3f3f3f3f;
const int INF=0x3f3f3f3f;
const int mod=1e9+7;
const int N=2e6+10;
int dx[4]={0,1,0,-1};
int dy[4]={-1,0,1,0};
void solve()
{
int n,a,b;
cin>>n>>a>>b;
if(n%b==0)
{
cout<<"YES"<<endl;
cout<<0<<' '<<n/b<<endl;
}else//n%b!=0
{
int k=1;
while(n-k*a>=0&&(n-k*a)%b!=0)k++;
if((n-k*a)%b==0&&(n-k*a)/b>=0)
{
cout<<"YES"<<endl;
cout<<k<<' '<<(n-k*a)/b<<endl;
}
else cout<<"NO"<<endl;
}
}
int main()
{
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
// freopen("test.in","r",stdin);
solve();
return 0;
}
时间复杂度$O(n)$
4297. 截断数组
思路:很明显题目的操作应该放到前缀上实现.
因此首先求出原数组的前缀数组,注意开long long.
然后枚举第一个区间的所有可能右边界.并从该边界开始二分的判断.是否存在和当前这种第一个区间前缀和相同的第三个区间即可。
注意由于$l$,$r$,可能会重叠需要特判一下$r>l$
AC Code:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>PII;
typedef unsigned long long ull;
const int M=2010;
const ll llINF=0x3f3f3f3f3f3f3f3f;
const int INF=0x3f3f3f3f;
const int mod=1e9+7;
const int N=2e6+10;
int dx[4]={0,1,0,-1};
int dy[4]={-1,0,1,0};
ll s[N];
int n;
bool check(int x)
{
ll sum1=s[x];
int l=x+1,r=n;
if(r<l)return false;
while(l<r)
{
int mid=l+r+1>>1;
if(s[n]-s[mid-1]>=sum1)l=mid;
else r=mid-1;
}
return s[n]-s[r-1]==sum1;
}
void solve()
{
cin>>n;
vector<ll>a(n+1);
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)s[i]=s[i-1]+a[i];//求前缀
for(int i=n;i>=1;i--)//
{
if(check(i))//i代表第一个区间的可能右边界
{
cout<<s[i]<<endl;
return;
}
}
cout<<0<<endl;
return;
}
int main()
{
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
// freopen("test.in","r",stdin);
solve();
return 0;
}
时间复杂度$O(n*\log n )$
4298. 搭档
思路:二分图的最大匹配问题。
建图的时候考虑$abs(a-b)<=1$连一条$a->b$的边即可。
AC Code:
#include<bits/stdc++.h>
using namespace std;
const int M=1e3+10;
const int N=1e5+10;
int e[N],ne[N],idx,h[M];
int match[M];
bool st[M];
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
bool find(int x)
{
for(int i=h[x];~i;i=ne[i])
{
int j=e[i];
if(!st[j])
{
st[j]=true;//标记下一当前这个被搜到的点
if(!match[j]||find(match[j]))
{
match[j]=x;
return true;
}
}
}
return false;
}
int main()
{
// freopen("test.in","r",stdin);
int n;
cin>>n;
vector<int>a(n+1);
for(int i=1;i<=n;i++)cin>>a[i];
int m;cin>>m;
vector<int>b(m+1);
for(int i=1;i<=m;i++)cin>>b[i];
sort(a.begin()+1,a.end());
sort(b.begin()+1,b.end());
memset(h,-1,sizeof h);//注意初始化邻接表 表头
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
if(abs(a[i]-b[j])<=1)add(i,j);//连接一条由A指向b的边
}
int ans=0;
for(int i=1;i<=n;i++)
{
memset(st,false,sizeof st);
if(find(i))ans++;
}
cout<<ans<<endl;
}
时间复杂度:$O(n*m)$
最后那题二分图匹配复杂度 $O(n\log n)$ 是开玩笑么
树的深度比较小。。。。
确实
已修正
比赛还没结束 算作弊了
其实最后一题两个数组排完序扫一遍就行了