A
题意:
给你一个递增的有序数组,问你是否存在一种情况(在这个数组里选三个数,使这三个数不可以构成三角形)。若存在,输出三个数得下标,否则输出-1。
思路:贪心,直接考虑极限情况a[1],a[2],a[n]是否满足条件即可,因为此时不满足即一定不会有满足条件得情况出现。
B
Alice 和 Bob 玩游戏,给他们一个只包含 1 和 0 得字符串 ,他们轮流操作,Alice 先手。
每个人每次可以选择拿掉连续的 x (x>=1) 个 0或1,每个人的得分是他们拿掉的1的数量,两个人都很聪明,问Alice的最大分数。
思路:
策略:每个人都会选择当前回合所能选择最多的1的数量。
简易证明:首先每个人都不会选0,因为选0,既不会给自己做出贡献,反而有可能给对方做出贡献,然后每个人选1的话一定会把1最多的那一堆的1全部拿完。(然后这一步不是很会证明,但很容易想到)。
C
题意:
给你一段长度为n的字符串,字符串只包含( ‘0’ - ‘9’ ) 。
问你这里面存在多少区间 [ l,r ] 使得 sum[r] - sum[l-1] = r - l + 1 ;
思路
这个题在比赛时我想复杂了,写了一个类似滑动数组的dp,后来发现他本质上用标记数组就可以实现不用滑动,后面会附上这两种代码的实现方式,主要说一下标记数组的实现,首先 (r-l+1) = 区间 [l,r] 内点的数量,这里把a[i]映射一下,0 ~ 9 -> -1 ~ 8 。
然后题意就变成了问存在多少个区间 [l,r] 使得sum[r] - sum[l-1] = 0(即sum[r] = sum[l])。 然后这里用标记数组实现就好了。
D
题意:
给你三种颜色的彩带,颜色分别是红绿蓝,数量分别是l1,l2,l3;
你每次可以选择两条颜色彩带构造矩形,然后获得一个分数是他们的长度之积,然后每个彩带只能被选择一次,问你可以获得的最大分数。
思路:
这个题比较有意思,他刚开始配合样例比较隐秘的诱导你往贪心哪里想,但是绝大多数(不好随便立flag)贪心是不对的,这里提供两组样例,想用贪心的可以仔细看看这两组数据。
2 2 4
9 9
9 9
8 8 8 8
2 4 6
10 10
10 10 10 10
10 10 10 10 10 10
好了,该说正解了,我写的是dp,dp[i] [j] [k] 代表选择i个红色彩带,j个绿色彩带,k个蓝色彩带 所能获得的最大值,具体方程看代码即可。
代码:
A
#include
using namespace std;
const int N=1e5+15;
typedef long long ll;
ll a[N];
int main()
{
ll t,n,ans;
cin>>t;
while(t--)
{
cin>>n; ans=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
if(n<3)
{
cout<<"-1"<<endl; continue;
}
if(a[1]+a[2]<=a[n])
{
cout<<"1 2 "<<n<<endl;
}
else
cout<<"-1"<<endl;
}
return 0;
}
B
#include
using namespace std;
const int N=1e3+15;
typedef long long ll;
ll a[N];
int main()
{
ll t,n,ans;
char str[N];
cin>>t;
while(t--)
{
scanf("%s",str+1);
n=strlen(str+1);
ans=0;
ll op=0,cnt=0;
str[n+1]='0';
for(int i=1;i<=n+1;i++)
{
if(str[i]=='1')
op++;
else
{
if(op!=0)
{
a[++cnt]=op; op=0;
}
}
}
sort(a+1,a+1+cnt);
for(int i=cnt;i>=1;i-=2)
{
ans+=a[i];
}
cout<<ans<<endl;
}
return 0;
}
C(滑动数组dp)
#include
using namespace std;
const int N=1e3+15;
typedef long long ll;
ll dp[4000000];
int a[1000000];
char str[300000];
int main()
{
ll t=1000,n=100,ans;
cin>>t;
while(t--)
{
cin>>n;
scanf("%s",str+1);
for(int i=1;i<=n;i++)
{
a[i]=int(str[i]-'0');
}
ans=2000000;
int minl=ans; int maxl=ans;
for(int i=1;i<=n;i++)
{
ans+=a[i];
int op=ans-i;
minl=min(minl,op); maxl=max(maxl,op);
dp[op]++;
}
ll sum=0;
sum+=dp[2000000];
int l=2000000;
for(int i=2;i<=n;i++)
{
ll d=a[i-1]-1;
dp[l+d]--; l+=d; sum+=dp[l];
}
for(int i=minl-10;i<=maxl+10;i++)
dp[i]=0;
printf("%lld\n",sum);
}
return 0;
}
C标记数组
#include
#include
using namespace std;
constexpr int kN = int(1E5 + 10);
int s[kN];
map<int, int> m;
void solve() {
int n;
string a;
long long int ans = 0;
cin >> n >> a;
for (int i = 1; i <= n; i++) s[i] = s[i - 1] + a[i - 1] - '0';
for (int i = 1; i <= n; i++) s[i] -= i;
m.clear();
m[0] = 1;
for (int i = 1; i <= n; i++) {
if (m.find(s[i]) != m.end()) ans += m[s[i]];
m[s[i]]++;
}
cout << ans << '\n';
}
int main() {
int t;
cin >> t;
while (t--) solve();
}
D
#include
using namespace std;
const int N=1e3+15;
typedef long long ll;
bool cmp(int a,int b)
{
return a>b;
}
int a[N],b[N],c[N];
ll dp[202][202][202];
int main()
{
ll la,lb,lc;
cin>>la>>lb>>lc;
for(int i=1;i<=la;i++)
cin>>a[i];
for(int i=1;i<=lb;i++)
cin>>b[i];
for(int i=1;i<=lc;i++)
cin>>c[i];
sort(a+1,a+1+la,cmp);
sort(b+1,b+1+lb,cmp);
sort(c+1,c+1+lc,cmp);
dp[1][1][0]=a[1]*b[1];
dp[1][0][1]=a[1]*c[1];
dp[0][1][1]=b[1]*c[1];
ll op1,op2,op3;
ll ans=0;
for(int i=0;i<=la;i++)
{
for(int j=0;j<=lb;j++)
{
for(int k=0;k<=lc;k++)
{
op1=0,op2=0,op3=0;
if(i>0&&j>0)
op1=dp[i-1][j-1][k]+a[i]*b[j];
if(i>0&&k>0)
op2=dp[i-1][j][k-1]+a[i]*c[k];
if(j>0&&k>0)
op3=dp[i][j-1][k-1]+b[j]*c[k];
op2=max(op1,op2); op3=max(op3,op2);
dp[i][j][k]=max(dp[i][j][k],op3);
ans=max(ans,dp[i][j][k]);
}
}
}
cout<<ans<<endl;
return 0;
}