A

求一个数是否有奇因子
一直除以二即可
代码
#include<bits/stdc++.h>
using namespace std;
int main()
{
// freopen("a.in","r",stdin);
// freopen("a.out","w",stdout);
int t;
scanf("%d",&t);
while(t--)
{
long long n;
scanf("%lld",&n);
while(n%2==0) n/=2;
if(n==1) printf("NO\n");
else printf("YES\n");
}
return 0;
}
B

求一个数是否能被表达成x2020+y2021=n的形式
如果n%2020的余数<=n/2020,就可以表示
代码
#include<bits/stdc++.h>
using namespace std;
int main()
{
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
int t;
scanf("%d",&t);
while(t--)
{
long long n;
scanf("%lld",&n);
int cnt=n/2020;
int yu=n-2020*cnt;
if(yu<=cnt) printf("YES\n");
else printf("NO\n");
}
return 0;
}
C


一道不错的容斥题,考虑每个男生和另一个男生的可以选择的组数的和,所以,然后再减去选重女生的可能
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
int n,m,k,a[maxn],b[maxn];
ll ans,sum,minn;
int cnta[maxn],cntb[maxn];
int main()
{
// freopen("a.in","r",stdin);
// freopen("a.out","w",stdout);
int t;
scanf("%d",&t);
while(t--)
{
ans=sum=minn=0;
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++) cnta[i]=0;
for(int i=1;i<=m;i++) cntb[i]=0;
for(int i=1;i<=k;i++) scanf("%d",&a[i]);
for(int i=1;i<=k;i++) scanf("%d",&b[i]);
for(int i=1;i<=k;i++)
{
cnta[a[i]]++;
cntb[b[i]]++;
}
for(int i=1;i<=n;i++)
sum+=cnta[i],minn+=1LL*cnta[i]*cnta[i];
minn/=2;
for(int i=1;i<=m;i++)
minn+=1LL*cntb[i]*(cntb[i]-1)/2;
ans=1LL*sum*sum/2-minn;
printf("%lld\n",ans);
}
return 0;
}
D


维护两个序列,从大到小放代价为1和代价为2的两组数
贪心的比较:两个1和一个2的内存之比,哪个大就选择哪个
注意还有几个需要注意的细节:1.最后有可能只需要一个代价为1的即可 2.最后一步选了一个代价为2的,可能超过所需删除的内存,可以撤销一次代价为1的操作,这里最多只有一次,可以考虑一下为什么
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
int n,m,a[maxn],b[maxn];
int cnta[maxn],cntb[maxn],pa,pb;
bool cmp(int x,int y)
{
return x>y;
}
int main()
{
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
int t;
scanf("%d",&t);
while(t--)
{
pa=pb=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) scanf("%d",&b[i]);
for(int i=1;i<=n;i++)
{
if(b[i]==1)
cnta[++pa]=a[i];
else cntb[++pb]=a[i];
}
sort(cnta+1,cnta+pa+1,cmp);
sort(cntb+1,cntb+pb+1,cmp);
ll mem=0;
cnta[pa+1]=cntb[pb+1]=0;
int ans=0,posa=0,posb=0;
while(mem<m && (posa<pa || posb<pb))
{
if(posb==pb || mem+cnta[posa+1]>=m)
{
ans++; posa++;
mem+=cnta[posa];
if(mem>=m) break;
else continue;
}
if(pa-posa>=2)
{
if(cnta[posa+1]+cnta[posa+2]>cntb[posb+1])
{
posa++; mem+=cnta[posa];
posa++; mem+=cnta[posa];
ans+=2;
}
else
{
posb++; mem+=cntb[posb];
ans+=2;
if(posa && mem-m>=cnta[posa])
{
ans--;
mem-=cnta[posa];
posa--;
}
}
}
else
{
ans+=2;
posb++; mem+=cntb[posb];
if(posa && mem-m>=cnta[posa])
{
ans--;
mem-=cnta[posa];
posa--;
}
}
}
if(mem<m) printf("-1\n");
else printf("%d\n",ans);
}
return 0;
}
E


给定一个序列,从中寻找和为最大的可能方案
排序后,枚举值为a[k]的个数cnt,在k以内的有cnta个,答案显而易见就是
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1005;
const ll MOD=1e9+7;
int n,m,a[maxn];
bool cmp(int x,int y)
{
return x>y;
}
ll c[maxn][maxn];
void C()
{
int i,j;
for(i=0;i<maxn;i++)
c[i][0]=c[i][i]=1;
for(i=1;i<maxn;i++)
for(j=1;j<=i;j++)
c[i][j]=(c[i-1][j]+c[i-1][j-1])%MOD;
}
int main()
{
// freopen("a.in","r",stdin);
// freopen("a.out","w",stdout);
int t;
scanf("%d",&t);
C();
while(t--)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
sort(a+1,a+n+1,cmp);
int dig=a[m],cnt=0,cnta=0;
for(int i=m;i>=1;i--)
{
if(a[i]!=dig) break;
cnt++; cnta++;
}
for(int i=m+1;i<=n;i++)
{
if(a[i]!=dig) break;
cnt++;
}
ll ans=c[cnt][cnta];
printf("%lld\n",ans);
}
return 0;
}
F

待续
本文介绍了五种算法问题的解决思路及代码实现,包括求奇因子、特定形式表达、容斥原理应用、序列维护与选择策略及最大组合求和等。
656

被折叠的 条评论
为什么被折叠?



