A. Select Three Sticks
题意:给我们一个n个数,然后还有两种操作,一种操作是将一个数减少1,另一种操作是将一个数增加1,然后问我们最小的操作次数使得能够从这n个数中,选择出三个相等的数
思路:首先我们将所有的数按照从小到达进行排序,然后我们进行两次选择,每一次选择都选择两侧中于当前点差值的绝对值更小且未被选择过的一侧,然后更新需要的最小花费,当遍历完所有点之后,ans既是答案
#include<iostream>
#include<cstring>
#include<vector>
#include<map>
#include<queue>
#include<unordered_map>
#include<cmath>
#include<cstdio>
#include<algorithm>
#include<set>
#include<cstdlib>
#include<stack>
#define forxn(i,a,n) for(int i=a;i<n;i++)
#define fordn(i,a,n) for(int i=a;i<=n;i++)
#define fornd(i,n,a) for(int i=n;i>=1;i--)
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=310 , M=110 , INF=0x3f3f3f3f;
const double eps=1e-6;
ll gcd(ll a,ll b) {return b==0?a:gcd(b,a%b);}
ll lcm(ll a,ll b) {return a*b/gcd(a,b);}
// int f[N];
// int find(int x) {if(f[x]!=x) f[x]=find(f[x]);return f[x];}
// int h[N],e[N],ne[N],idx;
// void add(int a,int b,int c) {e[idx]=b;ne[idx]=h[a];w[idx]=c;h[a]=idx++;}
// void add(int a,int b) {e[idx]=b;ne[idx]=h[a];h[a]=idx++;}
int T;
int n,m,k;
int w[N];
void solve() {
scanf("%d",&n);
fordn(i,1,n) scanf("%d",&w[i]);
sort(w+1,w+1+n);
int res=2e9;
fordn(i,1,n) {
int t=2;
int cnt=0;
int l=i-1,r=i+1;
while(t--) {
if(l<1) cnt+=abs(w[r++]-w[i]);
else if(r>n) cnt+=abs(w[l--]-w[i]);
else {
if(abs(w[l]-w[i])>=abs(w[r]-w[i])) cnt+=abs(w[r++]-w[i]);
else cnt+=abs(w[l--]-w[i]);
}
}
res=min(res,cnt);
}
printf("%d\n",res);
}
int main() {
scanf("%d",&T);
while(T--) solve();
return 0;
}
B. Bright, Nice, Brilliant
题意:给我们一个数n,代表这是一个n层的金字塔,然后第一层又1个房间,第二层有两个房间,第三层有三个房间,然后对于f(i,j)表示第i层的第j个房间,从上到下,从左到右进行编号,然后假如我们在(i,j)房间放上了一个手电筒,当前点以及f(i+1,j),f(i+1,j+1)能够接收到光照,以及所有能够接收到它的光照的点的下一层的对应房间与下一层的对应房间的下一个房间也都能接收到光照,然后让我们构造一种放手电筒的方案,使得对于某一层的所有房间能够接收到的光照数量相同。
思路:根据样例画一下,能够发现从第二层开始,每一层的开始跟末尾放一个手电筒,其余位置都不放,即可满足题意
#include<iostream>
#include<cstring>
#include<vector>
#include<map>
#include<queue>
#include<unordered_map>
#include<cmath>
#include<cstdio>
#include<algorithm>
#include<set>
#include<cstdlib>
#include<stack>
#define fordn(i,a,n) for(int i=a;i<=n;i++)
#define fornd(i,n,a) for(int i=n;i>=1;i--)
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=310 , M=110 , INF=0x3f3f3f3f;
const double eps=1e-6;
ll gcd(ll a,ll b) {return b==0?a:gcd(b,a%b);}
ll lcm(ll a,ll b) {return a*b/gcd(a,b);}
// int f[N];
// int find(int x) {if(f[x]!=x) f[x]=find(f[x]);return f[x];}
// int h[N],e[N],ne[N],idx;
// void add(int a,int b,int c) {e[idx]=b;ne[idx]=h[a];w[idx]=c;h[a]=idx++;}
// void add(int a,int b) {e[idx]=b;ne[idx]=h[a];h[a]=idx++;}
int T;
int n,m,k;
int w[N];
void solve() {
scanf("%d",&n);
fordn(i,1,n) {
if(i==1) printf("1\n");
else if(i==2) printf("1 1\n");
else {
int l=2,r=i-1;
printf("1 ");
fordn(j,l,r) printf("0 ");
printf("1\n");
}
}
}
int main() {
scanf("%d",&T);
while(T--) solve();
return 0;
}
C. Removing Smallest Multiples
题意:给我们一个n,代表着我们有一个包含1~n集合T,然后给我们一个长度是n的01串,其对应着一个集合S,对于为零的位置i来说,S中不包含i,然后又给我们一个操作,我们可以选择一个数k,然后我们能够用k的代价删除掉T中k的最小倍数,问我们最小的代价使得T变成S
思路:我们从头开始遍历,然后用一个st数组标记当前点是否被删除过,如果当前点str[i]=='0'代表当前点需要被删除,如果当前点还没有在之前被删除过,则res+=i,将该删除,之后我们再以它作为基数,删除掉后边i*k<=n&&str[i*k]=='0',当某个被判断的点已经被删除过时不能重复删除,然后直到找到第一个str[i*k]==1的点,因为如果我们再删除的话这个点将会被删除掉,如果当前点str[i]=='1'则直接跳过,这样遍历完整个01串之后就能得到答案,同时因为st在使用时只会用到后面的点,所以我们可以在循环的结尾顺便清空一下st数组,能够减少memset带来的时间
#include<iostream>
#include<cstring>
#include<vector>
#include<map>
#include<queue>
#include<unordered_map>
#include<cmath>
#include<cstdio>
#include<algorithm>
#include<set>
#include<cstdlib>
#include<stack>
#define forxn(i,a,n) for(int i=a;i<n;i++)
#define fordn(i,a,n) for(int i=a;i<=n;i++)
#define fornd(i,n,a) for(int i=n;i>=1;i--)
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=1e6+100 , M=110 , INF=0x3f3f3f3f;
const double eps=1e-6;
ll gcd(ll a,ll b) {return b==0?a:gcd(b,a%b);}
ll lcm(ll a,ll b) {return a*b/gcd(a,b);}
// int f[N];
// int find(int x) {if(f[x]!=x) f[x]=find(f[x]);return f[x];}
// int h[N],e[N],ne[N],idx;
// void add(int a,int b,int c) {e[idx]=b;ne[idx]=h[a];w[idx]=c;h[a]=idx++;}
// void add(int a,int b) {e[idx]=b;ne[idx]=h[a];h[a]=idx++;}
int T;
int n,m,k;
char str[N];
bool st[N];
void solve() {
scanf("%d",&n);
scanf("%s",str+1);
ll res=0;
fordn(i,1,n) {
if(str[i]=='0'&&!st[i]) res+=i;
int k=2;
while(str[i]=='0'&&k*i<=n&&str[k*i]=='0'){
if(st[k*i]) {
k++;
continue;
}
st[k*i]=true;
res+=i;
k++;
}
st[i]=false;
}
printf("%lld\n",res);
}
int main() {
scanf("%d",&T);
while(T--) solve();
return 0;
}