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;
}
京公网安备 11010502036488号