中山Day4——普及
生活开始日益平淡了呢。。。今天130分。
收获:归并排序求逆序对
背包问题(01、完全、多重)(外带滚动数组优化)
T1:题目链接(才不会告诉你们下面的代码也是洛谷上弄来的)
思路:动态规划。首先,设dp[i][k]为从a1到ak余数等于n的块数。然后先预处理一下,设sum[i][j]为从i到j%m的余数。接着用1至m-1来更新dp。
然后可以推出转移方程为:dp[i][(k*sum[j+1][i])%m]=max(dp[i][(k*sum[j+1][i])%m],dp[j][k]+1)。
这么做的时间复杂度是O(len^2*m),肯定是能过的。
见代码:
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; int n,m,a[1001],sum[1001][1001],dp[1001][100]; char c[1001]; int main() { for(int i=0;i<=1000;i++) for(int j=0;j<=50;j++) dp[i][j]=0x7f7f7f; scanf("%s%d",&c,&m); int len=strlen(c); for(int i=0;i<len;i++) a[i+1]=c[i]-'0'; for(int i=1;i<=len;i++) for(int j=i;j<=len;j++) sum[i][j]=(sum[i][j-1]*10+a[j])%m; for(int i=1;i<=len;i++) dp[i][sum[1][i]]=1; for(int i=1;i<=len;i++) { for(int j=1;j<i;j++) { for(int k=0;k<=m-1;k++) dp[i][(k*sum[j+1][i])%m]=min(dp[i][(k*sum[j+1][i])%m],dp[j][k]+1); } } for(int i=0;i<=m-1;i++) { if(dp[len][i]!=0x7f7f7f) { printf("%d %d ",i,dp[len][i]-1); break; } } for(int i=m-1;i>=0;i--) { if(dp[len][i]!=0x7f7f7f) { printf("%d %d ",i,dp[len][i]-1); break; } } return 0; }
好题哉!!!
T2:题目链接(这道我暴力冒泡30分)
思路:其实是很简单的,就是裸的归并排序找逆序对而已,可惜我早上不会,考到也算查漏补缺了。
见代码:
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; int n,a[500001],b[500001]; long long ans; void merge_sort(int l,int r) { if(r-l>0) { int mid=(l+r)/2; merge_sort(l,mid); merge_sort(mid+1,r); int i=l,q=mid+1,p=l; while(q<=r||p<=mid) { if(q>r||(p<=mid&&a[p]<=a[q])) { b[i++]=a[p++]; } else { b[i++]=a[q++]; ans+=mid-p+1; } } for(int i=l;i<=r;i++) a[i]=b[i]; } } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); merge_sort(1,n); printf("%ld",ans); return 0; }
好题哉!!!
T3:题目链接(唯一A掉的一道水题)
思路:第一眼看到k<=1018,就想到了以为叫做小凯的同学。于是就打了个表,发现是个斐波那契数列,然后就递推一下,外加维护一个前缀和,秒做的有没有。
见代码:
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; long long k,i; struct h{ long long num1; long long num2; long long q; }; h fb[90]; int main() { fb[0].num1=fb[0].num2=1; fb[0].q=1; scanf("%ld",&k); while(fb[i].q<k) { i++; fb[i].num2=fb[i-1].num1; fb[i].num1=fb[i-1].num1+fb[i-1].num2; fb[i].q=fb[i-1].q+fb[i].num2; } printf("m=%ld\n",fb[i].num2); printf("n=%ld",fb[i].num1); return 0; }
好题哉!!!
T4:题目链接
思路,最为清晰的一题:多重背包!!!可惜我又不会。。。恶补了下背包,以后就不会有问题啦,好开心
见代码:
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; int n,c,num,k=0,v[500001],w[500001],dp[500001]; int main() { scanf("%d%d",&n,&c); for(int i=1;i<=n;i++) { scanf("%d%d%d",&v[i],&w[i],&num); { for(int k=1;k<=num;k++) for(int j=c;j>=w[i];j--) { dp[j]=max(dp[j],dp[j-w[i]]+v[i]); } } } printf("%d",dp[c]); return 0; }
可惜这题不开单调队列优化就只有30分。诶……
好题哉!!!