目录
修改数组
本题纯属思维题!
结论:全部改成 1一定是最优解。
证明:
对于一个当前全部为 1 的区间 [l,r],考虑它与包含它的区间哪一个更优。考虑左端点左边一个位置 l−1,若 l−1 为 1 则左端点向左移显然更优;若 l−1 为 0,将 l−1 位置修改为 1 并将左端点向左移更优;此时 x 和 y 同时增大 1,x−y 不变
因此,一种最优的区间即为 [0,n-1],即将所有为 0 的数改为 1 时,x-y取到最大值,且为原序列中 1的个数。
代码:
#include<iostream>
using namespace std;
int main()
{
int T;
cin>>T;
while(T--)
{
int n;
cin>>n;
int res=0;
for(int i=0;i<n;i++)
{
int x;
cin>>x;
res+=x; //x-y最大值为原数组中1的个个数
}
cout<<res<<endl;
for(int i=0;i<n;i++)cout<<"1"<<' ';
puts(""); //快速换行,puts是换行最快的
}
return 0;
}
烦恼的高考志愿
这是一道二分题:二分出最后一个小于等于学生成绩的那个数
代码:
#include<iostream>
#include<algorithm>
using namespace std;
const int N=10100000;
int a[N],b[N];
int main()
{
int m,n;
cin>>m>>n;
for(int i=1;i<=m;i++)cin>>a[i];
for(int i=1;i<=n;i++)cin>>b[i];
sort(a+1,a+m+1); //先变成有序数组,再进行二分
int ans=0;
for(int i=1;i<=n;i++)
{
int l=0,r=m; //二分模板
while(l<r)
{
int mid=l+r+1>>1;
if(a[mid]<=b[i])l=mid; ///如果录取分数线数组中的第mid个元素小于或等于那位同学的分数,左边界就往右移
else r=mid-1;
}
if(a[1]>=b[i])ans+=a[1]-b[i]; //特判一下,如果所有录取分数线都比那位同学的分数低
else ans+=(min(abs(b[i]-a[l]),abs(b[i]-a[l+1])));
}
cout<<ans;
return 0;
}
水壶
考察前缀和
代码:
#include<iostream>
using namespace std;
const int N=1e6+10;
int a[N],s[N];
int main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i],s[i]=s[i-1]+a[i];//前缀和公式
int maxn=0;
for(int i=1;i+m<=n;i++){
int k=s[i+m]-s[i-1]; //前缀和计算
}
cout<<maxn;
return 0;
}
选数
本来打算用组合的dfs来写,但是去重问题自己还是不会搞,后来请教了一下大佬,用另一种方法解决了
代码1:(自己最初的错误版本)
#include<iostream>
#include<algorithm>
using namespace std;
const int N= 21;
int a[N],b[N]; //b[]存选出的k个数
bool st[N];
int m,res,k,n; //c为b[]选的数的和
bool is_prime(int x)
{
if(n<2) return false;
for(int i=2;i<=x/i;i++)
{
if(x%i==0) return false;
}
return true; //是素数就返回true
}
void dfs(int u)
{
if(u==k+1) //选到了k个数
{ int c=0;
for(int i=1;i<=k;i++)
{
c+=b[i];
}
if(is_prime(c))res++; //和为素数就加1
return ;
}
for(int i=1;i<=n;i++)
{
if(!st[i]) //a[]第i个数没选过
{
if(a[i]>b[m]) //b[]当前的数小于a[]第i个数(避免重复组合)
{
b[++m]=a[i];
st[i]=true; //标识a[]第i个数选过
dfs(u+1); //递归到下一位
st[i]=false;
--m;
}
}
}
return ;
}
int main()
{
cin>>n>>k;
for(int i=1;i<n+1;i++)cin>>a[i];
sort(a+1,a+n+1);
dfs(1);
cout<<res;
return 0;
}
代码2:(请教大佬后的ac代码)
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1000;
int a[N],b[N],s,res;
bool is_prime(int x)
{
if(x<2) return false;
for(int i=2;i<=x/i;i++)
{
if(x%i==0) return false;
}
return true;
}
void solve()
{ int n,m;
cin>>n>>m;
for(int i=1;i<n+1;i++)cin>>a[i];
for(int i=1;i<=m;i++)
{
b[i]=1;
}
do
{ s=0;
for(int i=1;i<=n;i++)
{
if(b[i]) s+=a[i];
}
if(is_prime(s))res++;
}
while(prev_permutation(b+1,b+1+n));
}
int main()
{
solve();
cout<<res;
return 0;
}
代码3:(另一种递归ac代码)
#include <iostream>
using namespace std;
const int N=22;
int num[N];
int n,k,ans;
bool isPrime(int n)
{
for(int i=2; i<n; i++)
{
if(n%i==0)return 0;
}
return 1;
}
int dfs(int i,int nums,int sum){ //i代表第i个数,nums代表已经加了几个数,sum代表nums个数之后的总和
if(nums==k){
if(isPrime(sum)){
ans++;
}
}
else if(i<=n){
dfs(i+1,nums,sum); //加:i+1(处理下一个数),sums+1,sum+num[i]
dfs(i+1,nums+1,sum+num[i]); //不加:就i+1(还是要处理下个数),nums,sum(不用动,因为没有加第i个数)dfs递归。
}
}
int main()
{
cin>>n>>k;
for(int i=1;i<=n;i++) cin>>num[i];
dfs(1,0,0);
cout<<ans;
return 0;
}