题意:给你一个序列,每次可以把一个元素移到最前面,问你移几次使得序列单增。
解法:偏思维, 做法比较多;
其实比较一下两个序列就好了;
#include<bits/stdc++.h> using namespace std; #define pb push_back typedef long long ll; const int N=1e5+5; ll a[N],b[N]; int main(){ int n, t; scanf("%d",&t); while(t--){ scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%lld",&a[i]),b[i]=a[i]; sort(b+1,b+1+n); int cnt=n; for(int i=n;i>=1;i--)if(b[cnt]==a[i])cnt--; printf("%d ",cnt); } return 0; }
G - G
题意:钓鱼,每个鱼钓的时间为ti,煮鱼的时间为k;问你怎么分配,使得时间最少;
解法:偏思维;
在ai%k的时间里,有两种选择,1.干等着,2.去捉鱼。
干等着:时间被浪费;
去钓鱼:保证桶里有鱼。
可以想一下,如果时间最少,那么锅的利用效率肯定最高,尽量不要让锅闲着。
那么每次在 ai%k 的时间里,如果手里有鱼,那么干等着就行了,反正锅里的鱼煮熟以后还能再放鱼,锅不会闲着;
如果手里没有鱼,那这段时间就要去捉鱼,因为不能锅闲着。
记录一下在煮鱼的时间里能钓的鱼为x,那么n-x条鱼就需要另外花k来钓;
那么有x条鱼,煮这这些鱼的时候干等着就行了,剩下的n-x就需要去钓其他鱼。
#include<cstdio> #include<algorithm> #include<queue> #define rep(i,j,k) for(int i=(int)j;i<=(int)k;i++) #define per(i,j,k) for(int i=(int)k;i>=(int)j;i++) #define pb push_back using namespace std; typedef long long ll; ll a[200005]; int main(){ int n,k,t; scanf("%d",&t); while(t--){ scanf("%d%d",&n,&k); ll ans=k,cnt=0; rep(i,1,n){ scanf("%d",&a[i]); ans+=a[i]/k*k; // cnt+=a[i]/k; a[i]%=k; } sort(a+1,a+1+n); ll x=ans/k; // if(x>n)x=n; x=min(x,n); ans+=(n-x)*k; for(int i=1;i<=x;i++)ans+=a[i]; printf("%lld ",ans); } return 0; }
F - F
题意:一个序列,每个数可以+1,-1,不变。但始终>0,问你最后形成的最大集合的元素个数。
做法:这题比较简单,搞错了一点,WA了几发;
贪心时先check ai-1,ai,ai+1;
要说也能明白,
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N=150001; ll a[N]; set<ll>st; int main(){ int n; scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%lld",&a[i]); sort(a+1,a+1+n); for(int i=1;i<=n;i++){ if(a[i]-1>0&&st.find(a[i]-1)==st.end())st.insert(a[i]-1); else if(a[i]>0&&st.find(a[i])==st.end())st.insert(a[i]); else if(a[i]+1>0&&st.find(a[i]+1)==st.end())st.insert(a[i]+1); } int ans=st.size(); cout<<ans<<endl; return 0; }
B - B
题意:线性dp,上楼可以楼梯,也可以电梯,每一步怎么走最快;
定义dpi0表示走楼梯到达i,dpi1,表示走电梯到达i;
有
dp[1][0]=0,dp[1][1]=inf;
dp[i][0]=min(dp[i-1][0]+a[i],dp[i-1][1]+a[i]);
dp[i][1]=min(dp[i-1][1]+b[i],dp[i-1][0]+c+b[i]);
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N=2e5+5; ll a[N],b[N]; ll dp[N][3]; int main(){ ll n,c; scanf("%lld %lld",&n,&c); a[0]=b[0]=0; for(int i=2;i<=n;i++)scanf("%lld",&a[i]); for(int i=2;i<=n;i++)scanf("%lld",&b[i]); dp[1][0]=0,dp[1][1]=0x3f3f3f3f; for(int i=2;i<=n;i++){ dp[i][0]=min(dp[i-1][0]+a[i],dp[i-1][1]+a[i]); dp[i][1]=min(dp[i-1][1]+b[i],dp[i-1][0]+c+b[i]); } for(int i=1;i<=n;i++){ ll ans=min(dp[i][0],dp[i][1]); printf("%lld%c",ans,i==n?' ':' '); } return 0; }
E - E
就是解个方程:x^x-(3+2*n)*x+n*n+n-2*k=0 ;
两个解,取小;
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N=2e5+5; ll a[N],b[N]; ll dp[N][3]; int main(){ ll n,c; scanf("%lld %lld",&n,&c); a[0]=b[0]=0; for(int i=1;i<n;i++)scanf("%lld",&a[i]); for(int i=1;i<n;i++)scanf("%lld",&b[i]); dp[1][0]=0,dp[1][1]=0x3f3f3f3f; for(int i=2;i<=n;i++){ dp[i][0]=min(dp[i-1][0]+a[i-1],dp[i-1][1]+a[i-1]); dp[i][1]=min(dp[i-1][1]+b[i-1],dp[i-1][0]+c+b[i-1]); } for(int i=1;i<=n;i++){ ll ans=min(dp[i][0],dp[i][1]); printf("%lld%c",ans,i==n?' ':' '); } return 0; }
D - D
题意:n*m的网格,如果有k*k的区间坏掉,那么盒子坏掉,让你找最小的答案;不会坏就是-1;
解法:千辛万苦,终于调出来一个TLE;
WA是这样的,没有考虑t=0的情况,如果一个点坏掉的时间是0呢?是不是也是合法的?所以初始化不应该0,而是-1;
感觉要初始化养成习惯吧,
考虑正确做法:蛋疼的调了很久,
做个sum数组来二维前缀和 ,二分出结果。
有
sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];
枚举每一个坏了的点,看看t能不能构成一个k*k的方块,
#include<bits/stdc++.h> using namespace std; #define pb push_back typedef long long ll; const int N=7e2+5; const int inf=0x7fffffff; int n,m,k,q; int sum[N][N]; struct point{int x,y,t;}points[N*N]; bool cmp(point A,point B){return A.t<B.t;} int check(int num){ memset(sum,0,sizeof sum); for(int i=1;i<=num;i++)sum[points[i].x][points[i].y]=1; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ sum[i][j]+=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]; } for(int i=k;i<=n;i++){ for(int j=k;j<=m;j++){ if(sum[i][j]-sum[i-k][j]-sum[i][j-k]+sum[i-k][j-k]==k*k) return 1; } } return 0; } int main(){ scanf("%d %d %d %d",&n,&m,&k,&q); for(int i=1;i<=q;i++){ scanf("%d %d %d",&points[i].x,&points[i].y,&points[i].t); } sort(points+1,points+1+q,cmp); int ans=-1; int l=1,r=q; while(l<=r){ int mid=(r+l)>>1; if(check(mid)){ans=points[mid].t;r=mid-1;} else l=mid+1; } printf("%d ",ans); return 0; }