B 题意:A[]中 第i人可以干掉i前连续A[i]个人,若每个人同时干掉敌人,问最后剩下几个人。
题解:从后往前扫一次,依次比较当前位置能杀死的最靠前的人位置 和 之前的人能杀死人的最早位置,O(n);
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double db;
typedef pair<int,int> pii;
typedef vector<int> vi;
#define de(x) cout << #x << "=" << x << endl
#define rep(i,a,b) for(int i=a;i<(b);++i)
#define all(x) (x).begin(),(x).end()
#define sz(x) (int)(x).size()
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define lb(x) (x&-(x))
const int N = 1010100;
int p[N];
int leftt=INT_MAX;
int main(){
int n;
cin>>n;
int cnt=0;
rep(i,1,n+1) scanf("%d",&p[i]);
for(int i=n;i>=1;i--)
{
if(leftt>i-p[i])
{
int aim=max((i-p[i]),1);
int j=min(i,leftt);
while(--j>=aim)
{
cnt++;
}
leftt=aim;
}
}
printf("%d\n",n-cnt);
return 0;
}
c题意:对于一个数组给出操作:用数组相邻元素x,y的gcd(x,y)代替x或y,问最少需要几步使数组元素全部变成1.
思路:只要让一个元素变成1,然后n-1次操作就能把其他所有元素变成1。
最优性证明:全部变成1的话,一定有个一个首先变成1,只要把第一个变成1的消耗加上n-1就是答案。
如果有1答案直接是n-1,如果没有1,为了把一个数变成1,我们可以找一个连续区间的GCD,这个区间满足GCD等于1且长度最短(这样我们把一个数变成1的消耗最小)。至于如何实现这一点,因为数组长度只有2000,可以O(n^2)枚举出最优情况即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double db;
typedef pair<int,int> pii;
typedef vector<int> vi;
#define de(x) cout << #x << "=" << x << endl
#define rep(i,a,b) for(int i=a;i<(b);++i)
#define all(x) (x).begin(),(x).end()
#define sz(x) (int)(x).size()
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define lb(x) (x&-(x))
const int N = 101010;
int a[2005];
int gcd(int a,int b)
{
if(a<b) swap(a,b);
if(a%b==0) return b;
else return gcd(a-b,b);
}
int qgcd(int a,int b)
{return a?qgcd(b%a,a):b;
}
int main(){
int n,num1=0;
int flag=0;
cin>>n;
rep(i,0,n) scanf("%d",&a[i]);
if(n==1&&a[0]==1) {
cout<<0<<endl;
return 0;
}
int mindis=9999;
int tmp;
rep(i,0,n)
{ tmp=a[i];
rep(j,i+1,n)
{ tmp=gcd(tmp,a[j]);
if(tmp==1&&j-i<=mindis)
{
mindis=j-i;
flag=1;
}
}
}
rep(i,0,n)if(a[i]==1) num1++;
if(flag) cout<<n-1-num1+mindis<<endl;
else cout<<-1<<endl;
return 0;
}