1.贪心:
1.如果10元,找5元
2.如果20元
a 优先5 和 10,因为尽量减少5,以免10不够找
b 其次 5 5 5
#include
using namespace std;
int a[2000000]={};
int read()
{
bool flag=true;
int num=0;char c=getchar();
for(;c<'0'||c>'9';c=getchar())if(c=='-') flag=false;
for(;c>='0'&&c<='9';c=getchar())
num=(num<<3)+(num<<1)+c-48;
if(flag) return num;
else return -num;
}
int main()
{
int n;
n=read();
for (int i=1;i<=n;i++)
{
int k;
k=read();
if (k==20)
{
if (a[5]>=1&&a[10]>=1)
{
a[5]-=2;
a[10]--;
continue;
}//5和10优先
else
if (a[5]>=3)
{
a[5]-=3;
continue;
}
else
{
cout<<"NO";
return 0;
}
}
if (k==10)
{
if (a[5]>=1)
{
a[5]--;
a[10]++;
continue;
}
else
{
cout<<"NO";
return 0;
}
}
if (k==5)
a[5]++;
}
cout<<"YES";
return 0;
}
2.可以看出,就是C(mn),也就是n选m 公式为:
n!
————
m!(n-m)!
可以无视坐标
20分程序如下:
#include
using namespace std;
const long long Mod=1000000007;
inline long long sum(long long N)
{
long long sum=1;
for (int i=2;i<=N;i++)
sum=sum*i;
return sum;
}
int main()
{
long long n,k;
cin>>n>>k;
cout<<sum(n)/(sum(k)*sum(n-k));
}
至于取模,除法是不可以直接取模的,需要用到逆元
我不懂。。
AC代码如下
#include
using namespace std;
long long x,n,k,Mod=1000000007,a=1,b=1,c,i,ans;
long long power(long long s,long long sum)
{
s=s%Mod;
ans=1;
while(sum)
{
if(sum&1)
ans=(ans*s)%Mod;
sum/=2;
s=(s*s)%Mod;
}
return ans%Mod;
}
int main()
{
scanf("%d%d",&n,&k);
for(i=1;i<=n;i++)
scanf("%d",&x);
for(i=1;i<=n;i++)
a=(a%Mod*i%Mod)%Mod;
for(i=1;i<=k;i++)
b=(b%Mod*i%Mod)%Mod;
for(i=1;i<=(n-k);i++)
b=(b%Mod*i%Mod)%Mod;
c=power(b,Mod-2)%Mod;
printf("%d",(a%Mod*c%Mod)%Mod);
return 0;
}
3.一道思维题
效率:O(n)。
#include
using namespace std;
int b[10000000]={};
int main()
{
int n,ans=-1,m,x;
cin>>n;
for (int i=1;i<=n;i++)
{
cin>>x;
m=max(m,x);
b[x]++;
}
int t=b[0];
for (int i=1;i<=m;i++)
t=(t+1)/2+b[i];//这句话表示剩下0的个数表示合并完的0和-1后为0的总和
ans=m;//最少为最大数,即-1的次数
while (t>1) t=(t+1)/2,ans++;//处理还剩下0的情况
cout<<ans;
}
4.贪心
如果(a[i]<0) 不做任何处理
否则就算
枚举:
从高位到低位依次枚举:
1.当该二进制位为0 不作处理
2.否则
a.当这位不取,则前面几位可以随便取,求前i-1为的最大值
b.同时累加这一位
c . b,c两步求最大值
#include
using namespace std;
long long n;
long long a[300000]={};
long long m[300000]={};
long long sum[300000]={};
long long s=0,ans=0;
char mm [1000000]={};
int main()
{
cin>>n;
for (long long i=1;i<=n;i++)
{
cin>>a[i];
if (a[i]>0) sum[i]=sum[i-1]+a[i];
else sum[i]=sum[i-1];//q前缀和
}
cin>>mm+1;
for (long long i=1;i<=n;i++)
m[i]=mm[i]-'0';
for (long long i=n;i>=1;i--)
if (m[i])
{
ans=max(ans,s+sum[i-1]);//求ab两步的最大值
s+=a[i];
}
cout<<max(ans,s);//最后别忘了判断哦
return 0;
}
5.二分答案:mid
表示每一个相邻的数字的差<=mid
DP验证:
f[i]表示前i位保留的数字的最大值(前提是每个差<=mid)
状态转移方程:f[i]=max(f[j]+1),条件是abs(a[i]-a[j])<=mid*(i-j),表示第i个数和第j个数相邻差满足条件
#include
using namespace std;
long long f[10000000]={};
long long n,k,in;
long long a[10000000]={};
inline bool check(long long x)
{
memset(f,0,sizeof(f));
for (long long i=1;i<=n;i++)
{
long long maxx=-100000000;
f[i]=1;
for (long long j=1;j<i;j++)
if ( abs(a[i]-a[j])<=x*(i-j) )
f[i]=max(f[i],f[j]+1);
}
long long in=-1;
for (long long i=1;i<=n;i++) in=max(in,f[i]);
return n-in<=k;
}
int main()
{
cin>>n>>k;
for (long long i=1;i<=n;i++)
cin>>a[i];
memset(f,0,sizeof(f));
long long left=0,right=9999999999,mid;
while (left+1<right)
{
mid=(left+right)/2;
if (check(mid)) right=mid;
else left=mid;
}
if (check(left)) cout<<left;
else cout<<right;
return 0;
}
6.前缀和
枚举左端点右端点,复杂度O(n^2)
至于分块怎么优化
.....................