A 数字计数
分析
较为基础,因为要最大最小,次大次小,可以先想到排序,但是不要忘了,数值中有重复的,所以还要去重。去重的方法有两种,一种是直接调用unique函数,另一种是遍历一遍将出现一次的计入数组
int main() { scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%d",&a[i]); sort(a+1,a+n+1); n=unique(a+1,a+n+1)-a-1; printf("%d %d %d %d\n",a[n]-a[n-1],a[n]-a[2],a[n-1]-a[2],a[n-1]-a[1]); return 0; }
分析 枚举每一个区间的开头,记录每一种颜色的出现次数,如果第一次出现就可以+1,然后ans统计答案O(n^2)
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
int ans=0;
for (int i=1;i<=n;i++)
{
int sum=0;
memset(cnt,0,sizeof(cnt));
for (int j=i;j<=n;j++)
{
if(cnt[a[j]]==0) sum++;
cnt[a[j]]++;
ans+=sum;
}
}
printf("%d\n",ans);
return 0;
}
还有一种就是O(n),记录这个颜色上一次出现的位置,设为x,pre[x],而这一段区间[pre[x],x]可以被加入(n-i+1)次
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
int ans=0;
for (int i=1;i<=n;i++)
{
ans+=(n-i+1)*(i-pre[a[i]]);
pre[a[i]]=i;
}
printf("%d",ans);
return 0;
}
枚举每一个区间的开头,记录每一种颜色的出现次数,如果第一次出现就可以+1,然后ans统计答案O(n^2)
还有一种就是O(n),记录这个颜色上一次出现的位置,设为x,pre[x],而这一段区间[pre[x],x]可以被加入(n-i+1)次
C 智斗恶龙
- 分析
题目中给出了n,m,sx,sy,d,x,想一想每一个的作用。n,m是地图的大小,d规定了人只能走到
abs(x-sx)+abs(y-sy)<=d的位置,而x是必须要选的个数。但是题目中说,即使到了某一个
点,也可以不取宝藏,那我就跑遍所有能到的点,记录宝藏的个数与值,去重,然后就可以求最小值了
#include<bits/stdc++.h> #define ll long long using namespace std; const int N=1100; int n,m,sx,sy,d,len;ll cnt; int dx[4]={1,0,-1,0}; int dy[4]={0,1,0,-1}; ll a[N][N],f[N][N],ans[N*N]; struct nk { int x,y; nk(int xx,int yy):x(xx),y(yy){} }; queue<nk>q; inline void Pre() { cnt=0; memset(f,0,sizeof(f)); } inline int check(int x,int y) { if(abs(x-sx)+abs(y-sy)>d) return 1; return x<1||x>n||y<1||y>m; } inline ll Get(int h,int l) { q.push(nk(h,l));f[h][l]=1; if(a[h][l]==-1) return -1; while(!q.empty()) { nk t=q.front();q.pop(); int x=t.x,y=t.y; if(a[x][y]>0) ans[++cnt]=a[x][y]; for (int i=0;i<4;i++) { int xx=x+dx[i]; int yy=y+dy[i]; if(check(xx,yy)) continue; if(f[xx][yy]) continue; if(a[xx][yy]==-1) continue; q.push(nk(xx,yy)); f[xx][yy]=1; } } ll op=1e17; sort(ans+1,ans+cnt+1); cnt=unique(ans+1,ans+cnt+1)-ans-1; if(cnt<len) return -1; for (ll i=1;i<=cnt;i++) { ll nex=i+len-1; if(nex>cnt) break; op=min(op,ans[nex]-ans[i]); } return op; } int main() { int T;scanf("%d",&T); while(T--) { Pre(); scanf("%d%d%d%d%d%d",&n,&m,&sx,&sy,&d,&len); for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) scanf("%lld",&a[i][j]); ll las=Get(sx,sy); if(las==-1) puts("no"); else printf("%lld\n",las); } return 0; }
D 能量水晶
- 分析
这是好题啊。因为题目中说要用到不能用为止。假设当前我还剩k的能量,说明已经没有消耗值小于k的法术了,那这是不是意味着我可以枚举我剩余的能量值,然后用我大于当前剩余容量的法术去凑出m-k的能量,这难道不是一个01背包求方案数?
/* */ #include<bits/stdc++.h> #define ll long long using namespace std; const int N=3100; ll n,m,ans; ll a[N],cnt[N]; int main() { scanf("%lld%lld",&n,&m); for (int i=1;i<=n;i++) scanf("%lld",&a[i]); sort(a+1,a+n+1); ll l=1; for (ll i=0;i<=m;i+=a[l],l++) {//枚举余下容量 ll rem=m-i; if(rem<0) break; memset(cnt,0,sizeof(cnt)); cnt[0]=1; for (ll j=l+1;j<=n;j++) for (ll k=rem;k>=a[j];k--) cnt[k]+=cnt[k-a[j]]; for (ll j=rem;j>=rem-a[l]+1;j--) ans+=cnt[j]; } printf("%lld\n",ans); return 0; }