小猴有两个数a,b他想知道两个数相乘后末尾0的个数,快来编写代码帮帮他吧!
a b
数据范围:
0≤a,b≤10^4
输出答案
50 2
2
50×2=100
有两个0,故答案为2.
#include
using namespace std;
int main(){
int n,m;
cin>>n>>m;
int k=n*m;
int nums=0;
if(!n||!m){
cout<<1;
return 0;
}
while(k){
int l=k%10;
if(!l){
nums++;
}
else{
break;
}
k/=10;
}
cout<<nums;
return 0;
}
如题还是上一题的找0,但是
0≤a,b≤10^14
a b
输出答案
30 50
2
#include
int main(){
char str1[19];
char str2[19];
scanf("%s %s",str1,str2);
if(strcmp(str1,"0")==0||strcmp(str2,"0")==0){
printf("1");
return 0;
}
int len1=strlen(str1);
int len2=strlen(str2);
char str3[19];
char str4[19];
int q,idx=0;
for( q=len1-1;q>=0;q--){
str3[idx++]=str1[q];
}
str3[idx]='\0';
idx=0;
for( q=len2-1;q>=0;q--){
str4[idx++]=str2[q];
}
str4[idx]='\0';
int ans[1000]={0};
for(int i=0;i<len2;i++){
int a=str4[i]-'0';
if(!a){
continue;
}
int index=i;
for(int j=0;j<len1;j++){
int b=str3[j]-'0';
ans[index++]+=a*b;
}
}
for(int i=0;i<1000;i++){
if(ans[i]>9){
ans[i+1]+=ans[i]/10;
ans[i]%=10;
}
}
int k=0;
for(int i=0;i<999;i++){
if(ans[i]==0){
k++;
}else{
printf("%d",k);
return 0;
}
}
return 0;
}
#include
long long a, b;
int solve(long long a, long long b) {
int cnt1 = 0, cnt2 = 0;
long long A = a, B = b;
while(A % 2 == 0)A /= 2, cnt1 ++;
while(B % 2 == 0)B /= 2, cnt1 ++;
while(a % 5 == 0)a /= 5, cnt2 ++;
while(b % 5 == 0)b /= 5, cnt2 ++;
return min(cnt1, cnt2);
}
int main(){
std::cin>>a>>b;
std::cout << solve(a, b);
}
WZ 学长最近迷恋上了泡养生茶,他买了枸杞,决明子,菊花,栀子,桑葚,桑叶,蒲公英,金银花,茯苓,人参… 某天他突发奇想,是不是把两杯液体重量一样的养生茶倒到其中一个杯子里面再喝下去,就会获得双倍的效果还能少喝一杯茶!(智慧的眼神)
说干就干!假设 WZ 学长一共有 n 杯养生茶,每个杯子无限大并且初始只有 1 升养生茶。WZ 学长每次只会把两杯质量一样的茶倒进其中一个杯子(别问我为什么要一样多),而他每次最多只愿喝 m 杯,那么他最少还需要再调配多少杯养生茶。
(放心如果要喝的养生茶超过 1 升,那么 WZ 就会把多的都送给 Jiejie 学长并且看着他喝完!)
输入第一行两个整数n和m,n 为 WZ 已有的养生茶杯数,m 为他愿意最多喝的养生茶数量
(0<m<n<100000000)
输出一行最少还需要再买多少杯
3 1
1
#include
#include
using namespace std;
int main(){
int n,m;
cin>>n>>m;
stack<int>s;
while(n--){
if(s.empty()){
s.push(1);
continue;
}
else{
int k=1;
while(!s.empty()){
if(s.top()==k){
k*=2;
s.pop();
}
else{
s.push(k);
break;
}
}
if(s.empty()){
s.push(k);
}
}
}
if(s.size()<=m){
cout<<0;
}
else{
int ret=0;
while(s.size()>m){
ret++;
int k=1;
while(!s.empty()){
if(s.top()==k){
k*=2;
s.pop();
}
else{
s.push(k);
break;
}
}
}
cout<<ret;
}
return 0;
}
链接:https://ac.nowcoder.com/acm/contest/72175/A
你得到一个正 N 边多边形。将任意一条边标记为边 1,然后按顺时针顺序将下一条边标记为边 2、3、N。在 i 侧有 Ai个特殊点。这些点的位置使得边 i 被分成长度相等的 Ai+1段。
您希望创建尽可能多的满足条件的三角形,同时满足以下要求。
请你数一数可以创建的满足条件的三角形的最大数量。
数据范围
3≤N≤200000 1≤Ai≤2⋅10^9
输出一个整数,表示可以创建的三角形的最大数量。
4
3 1 4 6
4
例如样例一,有一个正四边形。假设最上面的一条边被标记为边 1,下图显示了当 A=[3,1,4,6]时特殊点如何位于每一边内及一种可行的方案
#include
using namespace std;
int main(){
int n;
cin>>n;
long long int sum=0;
long long int cur=0;
for(int i=0;i<n;i++){
cin>>cur;
sum+=cur;
}
sum/=3;
cout<<sum;
return 0;
}
#include
#include
#include
using namespace std;
int main(){
int n;
cin>>n;
vector<int>v;
long long int sum=0;
long long int cur=0;
for(int i=0;i<n;i++){
cin>>cur;
v.push_back(cur);
sum+=cur;
}
long long int dot=sum;
sum/=3;
sort(v.begin(),v.end());
long long int max=v[n-1];
if(dot-max<sum){
cout<<dot-max;
}
else
cout<<sum;
return 0;
}
钟女士最近在备战六级,她在写好一篇作文后才发现自己的大小写做的一团糟,你能帮她统计批改大小写错误吗?
为了便于计算我们对大小写只做如下要求:
第一行n为单词个数,接下来为n个单词,每个单词以空格或回车隔开。
数据范围:1≤n≤1000
输出错误个数
8
welcoMe To programming contest. wish you every success.
4
welcoMe w需要大写,M需要小写
To 处于一句话中需要小写
wish w是新一句话的开头需要大写
#include
#include
#include
int main()
{
int n;
int ret = 0;
int head = 1;
scanf("%d", &n);
char str[100];
for (int i = 0; i < n; i++)
{
scanf("%s", str);
int len=strlen(str);
if (strcmp(str, "I") == 0 || strcmp(str, "I.") == 0 || head)
{
if (islower(str[0]))
ret++;
head = 0;
}
else if (strcmp(str, "i") == 0 || strcmp(str, "i.") == 0)
ret++;
else if (isupper(str[0]))
ret++;
for (int j = 1; j < len; j++)
{
if (isupper(str[j]))
ret++;
}
if (str[len - 1] == '.')
head = 1;
}
printf("%d", ret);
return 0;
}
n
,这个整数表示将要输入的字符串的数量。n
次。在每次循环中,程序都会获取一个字符串str
。head
变量表示),并且字符串的第一个字符是小写字母,那么ret
就会增加1。ret
就会增加1。ret
就会增加1。ret
就会增加1。head
就会被设置为1,表示下一个字符串应该是句子的开头。ret
的值,也就是违反英文句子大小写规则的情况的总数。有两个长度相等的字符串 a,b,它们只包含字符 0 或 1; 两个字符串都以字符 0 开始,以字符 1 结束。
您可以执行以下操作任意次数(可能为零):
选择其中一个字符串和两个相同的字符; 然后将它们之间的所有字符替换为这个字符。
T为测试用例数量,每个测试用例由 a,b两行组成
a,b都以字符 0 开始,以字符 1 结束
数据范围
2≤∣a∣=∣b∣≤5 0002,1≤T≤2 000
∑T(i=1)∣ai∣≤50 000
对于每个测试用例,如果可以使两个字符串相等,则打印YES否则,打印NO。
7
01010001
01110101
01001
01001
000101
010111
00001
01111
011
001
001001
011011
010001
011011
YES
YES
YES
NO
NO
NO
YES
#include
using namespace std;
string x,y;
int main(){
int n;
cin>>n;
while(n--){
cin>>x>>y;
if(x.size()!=y.size()){
cout<<"NO"<<endl;
continue;
}
if(x==y){
cout<<"YES"<<endl;
continue;
}
else{
bool flag = false;
for(int i=0;i<x.size();i++){
if(x[i]=='0'&&x[i+1]=='1'&&y[i]=='0'&&y[i+1]=='1'){
flag=true;
break;
}
}
if(flag){
cout<<"YES"<<endl;
}else{
cout<<"NO"<<endl;
}
}
}
return 0;
}
YES
,那么我们总能把两个字符串都变成 00…01…11 的形式,比如,对于其中的一个字符串,我们知道给定的字符串一定是有0在左,有1在右,如果其中不含任何一个0,或者不含任何一个1,那么他已经是000…01…11的形式,而中间只要存在01这样的子串,假如0是第n个,那么我们可以把1-n全部变成0,n+1到最后一个1全部变成1,而两个字符串相等,那么一定可以都变成00…01…11 的形式,所以我们只需要找是否存在这样的同下标的01字串就xin。给你一个长度为 N,仅包含小写字母的字符串 s,现要求你回答 Q 个询问:
数据范围:
2≤N≤10^6
1≤Q≤10^6
0≤l<r<N
std::cin.tie(0);
std::ios::sync_with_stdio(0);
输出 Q 行,第 i 行表示第 i 个询问的答案。
7 2
swpuacm
0 4
4 6
0
1
#include
#include
char str[1000005];
int ans[1000005] = {0};
int main(){
int len,q;
scanf("%d %d\n",&len,&q);
gets(str);
for(int i = 0; i < len-2; i++){
if(str[i] == 'a' && str[i+1] == 'c' && str[i+2] == 'm')
ans[i+2]=1;
ans[i+2]+=ans[i+1];
}
while(q--){
int l,r;
scanf("%d %d",&l,&r);
if(r-l<2){
printf("0\n");
}
printf("%d\n",ans[r]-ans[l+1]);
}
return 0;
}
#include
#include
char str[1000005];
int ans[1000005] = {0};
int main(){
int len,q;
scanf("%d %d\n",&len,&q);
gets(str);
for(int i = 0; i < len-2; i++){
if(str[i] == 'a' && str[i+1] == 'c' && str[i+2] == 'm')
ans[i+2]=1;
ans[i+2]+=ans[i+1];
}
while(q--){
int l,r;
scanf("%d %d",&l,&r);
printf("%d\n",ans[r]-ans[l+1]);
}
return 0;
}
if(r-l<2){
printf("0\n");
}
WZ 最近迷恋上了塔防益智小游戏,目标是尽可能多的净化敌方的区域,整个地图由“*”构成,敌方的地盘用“#”表示。每块敌方的地区 WZ 都需要派遣一位白骑士去净化,但是敌方为了保护自己的地盘建立了多个碉堡,每个碉堡用“!”表示。WZ 只能攻占一片敌方的区域,而这片区域每拥有一个碉堡 WZ 就需要多派一个白骑士去净化。问 WZ 想要尽可能多的净化敌方区域至少需要派遣多少个白骑士。
第一行,输入两个整数 n 和 m 代表整张地图的大小
接下来 n 行,每行将输入 m 个字符代表当前位置情况
1≤n,m≤500
x 代表 WZ 可以占领的敌方区域大小,y 代表 WZ 至少需要派遣多少个白骑士
4 4
#!**
!#**
*#*#
*#*!
6 8
#include
#include
#include
#include
using namespace std;
int x_m[4]={0,0,1,-1};
int y_m[4]={1,-1,0,0};
char str[501][501];
bool state[501][501];
int n,m;
vector<pair<int,int>>arr;
void bfs(int x, int y){
queue<pair<int, int>> q;
q.push(make_pair(x,y));
int cur_area = 0;
int cur_nums = 0;
while(!q.empty()){
pair<int, int> p = q.front();
q.pop();
cur_area++;
if(str[p.first][p.second]=='!'){
cur_nums+=2;
}
else{
cur_nums++;
}
for(int i=0;i<4;i++){
int x0=p.first+x_m[i];
int y0=p.second+y_m[i];
if(!state[x0][y0]&&str[x0][y0]!='*'&&x0>=0&&x0<n&&y0>=0&&y0<m){
state[x0][y0]=true;
q.push({x0, y0});
}
}
}
if(cur_area>0){
arr.push_back(make_pair(cur_area,cur_nums));
}
}
int main(){
cin>>n>>m;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cin>>str[i][j];
}
}
memset(state,false,sizeof(state));
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(str[i][j]!='*'&&!state[i][j]){
state[i][j]=true;
bfs(i,j);
}
}
}
int max=-1,idx=0;
for(int i=0;i<arr.size();i++){
if(arr[i].first>max){
max=arr[i].first;
idx=i;
}
}
cout<<max<<" "<<arr[idx].second;
return 0;
}
WZ 最近想要学卷积神经网络了!但是因为这是他第一次做这种项目,于是乎,,,一个拥有数不清 bug 的屎山就诞生了! 虽心有余想要全部删了重构,然而项目就快要结题了,只好央求我们英俊潇洒风流倜傥的 Jiejie 学长来挽救于危难之间。Jiejie 虽然看不懂问题到底出在了哪里,但他发现 WZ 的 bug 出现的很有规律,每个 bug 只会影响当前行的代码,为了 debug 的舒服他决定数行数行的进行修改。于是他决定帮 WZ 重构 mmm 个片段(即从一个 bug 到另一个 bug 算一个片段),于是想问 Jiejie 学长最少需要重构多少行代码。
第一行输入代码总长度 x 和 n 个 bug 以及 Jiejie 愿意重构 m 个片段数
第二行一共有 n 个数字代表每个 bug 的位置
数据范围:
1≤ai≤x1
1≤x,n,m≤10000
Jiejie 学长最少需要更改的行数
11 5 2
2 4 6 9 10
5
对于样例的一些解释:即2到4需要改4-2行代码,4到6需要改2行代码,6到9需要改3行代码,9到10需要改1行代码,因此为了尽可能少的修改,删去6到9的3行,改2+2+1=5行。
#include
#include
#include
using namespace std;
int main(){
vector<int>v1;
vector<int>v2;
int all,n,m;
cin>>all>>n>>m;
for(int i=0;i<n;i++){
int k;
cin>>k;
v1.push_back(k);
}
sort(v1.begin(),v1.end());
for(int i=0;i<v1.size()-1;i++){
int k=v1[i+1]-v1[i];
v2.push_back(k);
}
sort(v2.begin(),v2.end());
int ret=0;
for(int i=n-m-1;i>=0;i--){
ret+=v2[i];
}
cout<<ret;
return 0;
}
我们有一个盒子,初始时是空的。 让我们按照输入中给出的顺序执行以下两种类型的一共Q操作。
x 类型1:向盒子里放入一个写有整数x的球。
x 类型2:从盒子里取出一个写有整数x的球。 保证在执行操作前盒子里已经有一个写有整数x的球。
对于每次操作后的盒子,解决以下问题。
找到从盒子里取出一些球整数之和为K的方案数,模998244353。 盒子里所有的球都是可以区分的。
所有输入值都是整数。
1≤Q≤5000 1≤K≤5000
对于每种类型的操作
- x 表示从盒子取出一个x小球
+ x 表示从盒子加入一个x小球
1≤x≤5000
所有的操作都满足问题陈述中的条件。
盒子里取出一些球整数之和为K的方案数%998244353
15 10
+ 5
+ 2
+ 3
- 2
+ 5
+ 10
- 3
+ 1
+ 3
+ 3
- 5
+ 1
+ 7
+ 4
- 3
0
0
1
0
1
2
2
2
2
2
1
3
5
8
5
#include
#include
const int mod = 998244353;
using namespace std;
int main() {
long long int n, k;
cin >> n >> k;
vectordp(k + 1);
dp[0] = 1;
while (n--) {
char c;
cin>>c;
int ball;
cin>>ball;
if (c == '-') {
for (int i = ball; i <= k; i++) {
(dp[i] -= dp[i - ball]) %= mod;
}
}
else {
for (int i = k; i >= ball; i--) {
(dp[i] += dp[i - ball]) %= mod;
}
}
cout << (dp[k] + mod) % mod << endl;
}
return 0;
}
dp
,其中dp[i]
表示整数之和为i
的方案数。初始时,dp[0]
为1,表示没有取出任何球的方案数为1。dp
数组:x
的球,我们就需要更新dp[j+x]
,其中j
从k-x
到0。这是因为,现在我们有了一个新的球,可以用来组成新的整数之和。所以,对于所有小于或等于k-x
的j
,我们都可以通过在原来的方案中加上这个新的球,得到一个整数之和为j+x
的新方案。因此,我们需要将dp[j]
加到dp[j+x]
上。x
的球,我们就需要更新dp[j]
,其中j
从x
到k
。这是因为,我们失去了一个可以用来组成整数之和的球。所以,对于所有大于或等于x
的j
,我们都需要从dp[j]
中减去那些包含这个球的方案。因此,我们需要将dp[j-x]
从dp[j]
中减去。最后,dp[k]
就是我们想要的答案,即从盒子里取出一些球,使得这些球的整数之和为K
的所有可能方案数。
给定一个网格,某机器人从网格的左上角出发,它只能向下走或向右走。机器人很傻,它只会遵循设定好的策略,严格按照某种概率来决定往哪个方向走。比如在样例中的起点位置,机器人有0.3的概率向下走,有0.7的概率向右走。每个网格有一定的价值,机器人每到达一个网格可以收割该网格的价值。现在问你,机器人从出发到离开网格,它能收割价值的期望是多少?
第一行输入正整数n, m代表网格是n行m列的
接下来n行,每行输入m个整数,对于每个整数v,它代表每个网格的价值
接下来n行,每行输入m个整数,对于每个整数p,它代表机器人在该网格向下走的概率是p / 100
输出共一行,输出机器人能收割价值的期望,四舍五入保留到整数
1≤n,m≤1000
0≤v≤1000
0≤p≤1000
对于任意一个网格,机器人向下走的概率和向右走的概率之和为1
2 2
15 7
21 99
30 10
50 40
48
一共有六种可能的路径:
15 -> 7 -> right,这条路径的价值为15 + 7 = 22,概率为0.7 * 0.9 = 0.63
15 -> 7 -> 99 -> right,这条路径的价值为15 + 7 + 99 = 121,概率为0.7 * 0.1 * 0.4 = 0.028
15 -> 7 -> 99 -> down,这条路径的价值为15 + 7 + 99 = 121,概率为0.7 * 0.1 * 0.6 = 0.042
15 -> 21 -> down,这条路径的价值为15 + 21 = 36,概率为0.3 * 0.5 = 0.15
15 -> 21 -> 99 -> down,这条路径的价值为15 + 21 + 99 = 135,概率为0.3 * 0.5 * 0.4 = 0.06
15 -> 21 -> 99 -> right,这条路径的价值为15 + 21 + 99 = 135,概率为0.3 * 0.5 * 0.6 = 0.09
所以期望 = 22 * 0.63 + 121 * 0.028 + 121 * 0.042 + 36 * 0.15 + 135 * 0.06 + 135 * 0.09 = 47.98
#include
#include
using namespace std;
const int MAX_SIZE = 1005;
int values[MAX_SIZE][MAX_SIZE] = {0};
int parr[MAX_SIZE][MAX_SIZE] = {0};
double dp[MAX_SIZE][MAX_SIZE] = {0};
int main(){
int n, m;
cin >> n >> m;
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
cin >> values[i][j];
}
}
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
cin >> parr[i][j];
}
}
for(int i = n-1; i >= 0; i--){
for(int j = m-1; j >= 0; j--){
{
dp[i][j] = dp[i+1][j] * (parr[i][j] / 100.0) + dp[i][j+1] * (1 - parr[i][j] / 100.0) + values[i][j];
}
}
}
int ans=(int)(dp[0][0]+0.5);
cout<<ans;
}
(i, j)
,我们有两种可能的移动方式:向右和向下。如果我们向右移动,那么我们会加上 dp[i][j+1] * (1 - parr[i][j] / 100.0)
到 dp[i][j]
。这个表达式的含义是,如果我们向右移动,那么我们会到达点 (i, j+1)
,从这个点到终点的所有可能路径的期望之和是 dp[i][j+1]
,而向右移动的概率是 1 - parr[i][j] / 100.0
,所以我们需要将 dp[i][j+1]
乘以这个概率。同理,如果我们向下移动,我们需要将 dp[i+1][j] * (parr[i][j] / 100.0)
加到 dp[i][j]
。最后,我们需要加上当前点的值 values[i][j]
,因为无论我们选择哪种移动方式,我们都会经过当前点。而仔细观察我们可以发现,我们可以把二维数组开的大一些,并把点之外的值设置为0,这样就可以合并两种情况,反正为期望0,不会影响到那一部分的计算。而为什么要加上values[i][j]
,很简单,对于每一步,他只存在两种走法,且都会经过它本身,所以对于该点,它的概率为1,期望就是它本身。给定N个在二维平面上的不同点。第i个点(1≤i≤N)的坐标为(xi, yi)。
我们定义两点i和j之间的距离为min(∣xi−xj∣,∣yi−yj∣):x坐标和y坐标差值中的较小者。
找出两个不同点之间的最大距离。
2≤N≤200000
0≤xi,yi≤10^9
(xi,yi) ≠ (xj,yj) (i≠j)
所有输入值都是整数。
打印两个不同点之间的最大距离。
3
0 3
3 1
4 10
4
#include
#include
#include
#define dot 200005
using namespace std;
struct pos{
int x;
int y;
};
int n;
bool compare(struct pos &a, struct pos &b) {
return a.x < b.x;
}
struct pos all[dot];
bool check(int mid){
int mmin=1e9+5,mmax=-1;
for(int i=0,j=0;i<n;i++){
while(j<i&&all[i].x-all[j].x>=mid){
mmin = min(mmin, all[j].y);
mmax = max(mmax, all[j].y);
++j;
}
if(all[i].y-mmin>=mid||mmax-all[i].y>=mid) return false;
}
return true;
}
int main(){
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin>>n;
for(int i=0;i<n;i++){
cin >> all[i].x >> all[i].y;
}
sort(all,all+n,compare);
int l=0,r=1e9,mid;
while(l<r){
mid=(l+r+1)>>1;
if(check(mid)) r=mid-1;
else l=mid;
}
cout<<l<<endl;
return 0;
}
struct pos
:定义了一个结构体来表示点,包含x和y两个坐标。compare
函数:这是一个比较函数,用于sort
函数。它比较两个点的x坐标,如果点a的x坐标小于点b的x坐标,就返回true
。check(int mid)
:这个函数用于检查是否存在两个点,它们之间的距离大于或等于mid
。函数首先初始化最小值mmin
和最大值mmax
,然后遍历所有的点。对于每一个点,它会检查是否存在一个j(j < i),使得all[i].x - all[j].x >= mid
。如果存在,那么就更新mmin
和mmax
,并且检查all[i].y - mmin >= mid
或者mmax - all[i].y >= mid
是否成立。如果成立,那么就返回false
,否则继续检查下一个点。main()
:主函数首先读入点的数量n,然后读入每一个点的坐标。接着,它会根据x坐标对所有的点进行排序。然后,使用二分查找的方法来找出最大的距离。具体来说,它会不断地取中间值mid
,并使用check(mid)
来检查是否存在两个点,它们之间的距离大于或等于mid
。如果存在,那么就更新右边界r
,否则就更新左边界l
。最后,输出左边界l
,这就是两个不同点之间的最大距离。给出一个长度为n的a数组 你有k次机会可以对其中任一元素±1 问最长的公差为114514的等差数列长度
n为数组长度,k为机会次数,ai为长度为n的数组中的元素1≤n≤2×10^5
0≤k≤10^15
0≤ai≤10^9
一个数 表示能找到公差为114514的等差数列的最长长度
7 572570
7 2 5 5 4 11 7
4
#include
using namespace std;
const int N = 2e5+10;
#define int long long
#define PII pair<int,int>
struct node{
int l,r,v,cnt;
}tr[N<<2];
int n,m,a[N],mpp[N];
void pushup(int i) {
auto &u = tr[i], &l = tr[i << 1], &r = tr[i << 1 | 1];
u.v = l.v + r.v;
u.cnt = l.cnt + r.cnt;
}
void build(int i,int l,int r) {
tr[i].l = l, tr[i].r = r, tr[i].cnt = 0, tr[i].v = 0;
if (l == r) {
return;
}
int mid = l + r >> 1;
build(i << 1, l, mid);
build(i << 1 | 1, mid + 1, r);
}
void modify(int i,int x,int k,int k2) {
if (tr[i].l >= x && tr[i].r <= x) {
auto &u = tr[i];
u.v += k;
u.cnt += k2;
return;
}
if (tr[i].l > x || tr[i].r < x)return;
if (tr[i << 1].r >= x)modify(i << 1, x, k, k2);
if (tr[i << 1 | 1].l <= x)modify(i << 1 | 1, x, k, k2);
pushup(i);
}
int query(int i,int f) {
if (tr[i].l == tr[i].r) {
return tr[i].l;
}
if (tr[i << 1].cnt >= f)return query(i << 1, f);
else return query(i << 1 | 1, f - tr[i << 1].cnt);
}
PII query(int i,int l,int r) {
PII res = {0, 0};
if (tr[i].l >= l && tr[i].r <= r) {
auto &u = tr[i];
return {u.v, u.cnt};
}
if (tr[i].l > r || tr[i].r < l)return res;
if (tr[i << 1].r >= l) {
PII now = query(i << 1, l, r);
res.first += now.first;
res.second += now.second;
}
if (tr[i << 1 | 1].l <= r) {
PII now = query(i << 1 | 1, l, r);
res.first += now.first;
res.second += now.second;
}
return res;
}
void solve() {
cin >> n >> m;
map<int, int> mp;
for (int i = 1; i <= n; i++) {
cin >> a[i];
a[i] -= i;
mp[a[i]]++;
}
int idx = 0;
for (auto[pos, w]: mp) {
++idx;
mp[pos] = idx;
mpp[idx] = pos;
}
int ans = 1;
build(1, 1, n);
for (int i = 1, j = i; i <= n && j <= n; i++) {
while (j <= n) {
modify(1, mp[a[j]], a[j], 1);
int mid = j - i + 1;
int z = mpp[query(1, (mid + 1) / 2)];
auto[lv, lcnt]=query(1, 1, mp[z]);
auto[rv, rcnt]=query(1, mp[z] + 1, idx);
if (lcnt * z - lv + rv - rcnt * z <= m) {
ans = max(ans, mid);
j++;
} else {
modify(1, mp[a[i]], -a[i], -1);
modify(1, mp[a[j]], -a[j], -1);
break;
}
}
}
cout << ans << '\n';
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;cin >> t;
while (t--) {
solve();
}
}
数据结构:这个程序使用了一个名为node
的结构体来存储线段树的节点信息,包括左端点l
,右端点r
,区间和v
和区间内元素个数cnt
。线段树是一种用于存储区间或线段信息的数据结构,可以高效地进行区间查询和更新操作。
预处理:在solve
函数中,首先读入数组的长度n
和可以改变的次数m
,然后读入数组a
。接着,对数组a
进行预处理,将每个元素减去其下标,然后将处理后的元素存入一个映射mp
中。
构建线段树:然后,构建线段树,用于存储数组中的元素信息。
主循环:在主循环中,遍历数组中的每个元素,对每个元素进行查询和修改操作,以找出最长的满足条件的等差数列长度。具体来说,对于每个元素,首先将其加入线段树,然后查询线段树中的信息,如果满足条件(即改变元素的次数不超过m
),则更新答案,否则将元素从线段树中移除。
输出结果:最后,输出找到的最长等差数列的长度。