A题,按照题意判断一下就行了
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int t,n,m,a[N],b[N];
bool vis[N];
int main()
{
scanf("%d",&t);
while(t--)
{
int k1,k2,w,b;
scanf("%d%d%d%d%d",&n,&k1,&k2,&w,&b);
int kmi=min(k1,k2),kma=max(k1,k2);
if(kmi+(kma-kmi)/2>=w&&(n-kma)+(kma-kmi)/2>=b)puts("YES");
else puts("NO");
}
return 0;
}
B题,看能不能把字符串变成前面是0后面是1,但是不能同时改变相邻的2个
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int t,n,m,a[N],b[N];
bool vis[N];
string s;
int main()
{
scanf("%d",&t);
while(t--)
{
cin>>s;
int n=s.size();
bool f=0;
for(int i=0;i<n;i++)
{
if(!f&&s[i]=='1')
{
s[i]='0';
if(s[i+1]=='1')f=1;
i++;
}
else if(f&&s[i]=='0')
{
s[i]='1';
i++;
}
}
bool ff=0;
for(int i=1;i<n;i++)if(s[i]-s[i-1]<0)
{
ff=1;
break;
}
if(ff)puts("NO");
else puts("YES");
}
return 0;
}
C题,把奇数位当作是往右走,把偶数位当作往上走
最优解的情况一定是把最多的步数放再最小段上,其他段只走一步
预处理
s
u
m
a
suma
suma,和
s
u
m
b
sumb
sumb,然后遍历更新
a
n
s
ans
ans,在最后遍历出最小花费
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int t,n,m;
ll a[N],b[N],ans[N],suma[N],sumb[N];
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
ll x;
scanf("%lld",&x);
if(i&1)a[i]=x,suma[i]=suma[i-1]+x,sumb[i]=sumb[i-1];
else b[i]=x,sumb[i]=sumb[i-1]+x,suma[i]=suma[i-1];
}
ans[2]=a[1]*n+b[2]*n;
ll ma=a[1],mb=b[2];
for(int i=3;i<=n;i++)
{
if(i&1)
{
ll k=i/2;
if(a[i]<ma)ans[i]=ans[i-1]-(n-k)*(ma-a[i]);
else ans[i]=ans[i-1]-ma+a[i];
}
else
{
ll k=(i-1)/2;
if(b[i]<mb)ans[i]=ans[i-1]-(n-k)*(mb-b[i]);
else ans[i]=ans[i-1]-mb+b[i];
}
if(i&1)ma=min(ma,a[i]);
else mb=min(mb,b[i]);
}
ll res=(1ll<<60);
for(int i=2;i<=n;i++)
res=min(res,ans[i]);
cout<<res<<'\n';
}
return 0;
}
D题,首先要知道
l
c
m
(
a
,
b
)
lcm(a,b)
lcm(a,b)=
a
∗
b
/
g
c
d
(
a
,
b
)
a*b/gcd(a,b)
a∗b/gcd(a,b),下面用
g
g
g表示
g
c
d
(
a
,
b
)
gcd(a,b)
gcd(a,b)
即求
a
∗
b
∗
c
/
g
−
d
∗
g
=
x
a*b*c/g-d*g=x
a∗b∗c/g−d∗g=x ,而
a
a
a可以表示成
g
∗
k
1
g*k1
g∗k1,
b
b
b可以表示成
g
∗
k
2
g*k2
g∗k2,其中
k
1
k1
k1和
k
2
k2
k2互质。
用令
k
=
k
1
∗
k
2
k=k1*k2
k=k1∗k2,那么上式就变成了
g
∗
(
k
∗
c
−
d
)
=
x
g*(k*c-d)=x
g∗(k∗c−d)=x,那么
k
=
(
x
/
g
+
d
)
/
c
k=(x/g+d)/c
k=(x/g+d)/c,其中
x
x
x %
g
=
0
g=0
g=0,
(
x
/
g
+
d
)
(x/g+d)
(x/g+d)%
c
=
0
c=0
c=0,这题就变成了求有多少
(
k
1
,
k
2
)
(k1,k2)
(k1,k2)对,因为
k
k
k是2个互质的数的乘积,那么就需要知道
k
k
k有多少个质因子。
比如
k
=
2
∗
2
∗
3
∗
5
k=2*2*3*5
k=2∗2∗3∗5,有3个质因子
(
k
1
,
k
2
)
(k1,k2)
(k1,k2)可以为
(
1
,
2
∗
2
∗
3
∗
5
)
(1,2*2*3*5)
(1,2∗2∗3∗5),
(
2
∗
2
,
3
∗
5
)
(2*2,3*5)
(2∗2,3∗5),
(
3
,
2
∗
2
∗
5
)
.
.
.
.
(3,2*2*5)....
(3,2∗2∗5)....
不难发现规律,
(
k
1
,
k
2
)
(k1,k2)
(k1,k2)的组数为
C
(
3
,
0
)
+
C
(
3
,
1
)
+
C
(
3
,
2
)
+
C
(
3
,
3
)
=
2
3
C(3,0)+C(3,1)+C(3,2)+C(3,3)=2^3
C(3,0)+C(3,1)+C(3,2)+C(3,3)=23
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e7+10;//k1*k2的最大值为2e7
int prim[N],cnt[N],cc;//cnt[i]表示i这个数有多少个质因子
bool vis[N];
ll ans=0;
int c,d,x;
void init(int n){
for(int i=2;i<=n;i++)
{
if(!vis[i])prim[++cc]=i,cnt[i]=1;
for(int j=1;prim[j]<=n/i;j++)
{
vis[i*prim[j]]=1;
if(i%prim[j]==0)//如果i含有prim[j]这个因子
{
cnt[i*prim[j]]=cnt[i];
break;
}
else cnt[i*prim[j]]=cnt[i]+1;
}
}
}
void work(int k)
{
if(((x/k)+d)%c)return;
int p=((x/k)+d)/c;
ans+=1<<cnt[p];
}
int main()
{
int t;
scanf("%d",&t);
init(N-1);
while(t--)
{
ans=0;
scanf("%d%d%d",&c,&d,&x);
for(int i=1;i*i<=x;i++)
{
if(x%i==0)
{
work(i);
if(i*i!=x)work(x/i);
}
}
cout<<ans<<'\n';
}
return 0;
}