haue_oj_题目总结附md语法说明(1)


¥¥¥¥跳转题目或语法说明

1417后面的代码跳转

md语法说明



1355 好几个数

题目描述:
MX有一个有(w- 2)个数的集合S= {3,4,5,… ,w}。要求构造一个只包含非负整数的集合(无重复元素),
使得S里面的任何-个数都能被这个集合里面大于等于3个不同的数相加得到,求这个集合中至
少包含多少个元素。

输入:
本题包含多组测试数据。
第一行输入-个整数T,表示数据组数。
接下来T行每行输入一个整数w.

输出
共T行,每行输出一个整数n,表示集合至少应该含有的元素个数。

#include<iostream>
#include<cmath>
	
using namespace std;

int main(){

    int t;
    cin>>t;
	while(t--){
    	long long  x;
        cin>>x;
        long long  cnt=3,sum=3;
        while(sum<x){
     		sum*=2;
     		cnt++;
		}	
  		cout<<cnt<<endl;
    }
    
    
    
	return 0;
}


1356 旋转矩阵

题目描述:
在n x n二维数组上将一个奇数阶方阵按照顺时针或者逆时针旋转
首先,YX会把1到n^2的正整数按照从左往右,从上至下的顺序填入初始的二维数组中,然后提供给你ta的魔法执行顺序,想让你来告诉ta魔法按次执行完毕后的二维数组。

输入:
第一行两个整数n, m,表示方阵大小和魔法施放次数。
接下来m行,每行4个整数x, y,r,z,表示在这次魔法中,ta会把以第x行第y列为中心的2r +1阶矩阵按照某种时针方向旋转,其中z=0表示顺时针,z=1表示逆时针。

输出
输出n行,每行n个用空格隔开的数,表示最终所得的矩阵

#include<bits/stdc++.h>
using namespace std;
int g[510][510],tot,f[510][510];//f数组充当临时数组 
int main(){
	int n,m;
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			g[i][j]=++tot;
	for(int i=1;i<=m;i++) {
		int a,b,r,opt;
		scanf("%d %d %d %d",&a,&b,&r,&opt);//下面的分析都是针对那一块矩阵而言的 
		if(opt==0) {//第i行第j个 变成倒数第i列第j个 顺时针 
			for(int i=a-r;i<=a+r;i++)
				for(int j=b-r;j<=b+r;j++)
					f[a-b+j][a+b-i] = g[i][j];
			for(int i=a-r;i<=a+r;i++)
				for(int j=b-r;j<=b+r;j++)
					g[i][j] = f[i][j];
		}
		else { //第i行第j个 变成第i列倒数第j个 逆时针 
			 for(int i=a-r;i<=a+r;i++)
				for(int j=b-r;j<=b+r;j++)
					f[a+b-j][b-a+i] = g[i][j];
			 for(int i=a-r;i<=a+r;i++)
				for(int j=b-r;j<=b+r;j++)
					g[i][j] = f[i][j];
		}
	}
	for(int i=1;i<=n;i++) {//输出结果咯 
		for(int j=1;j<=n;j++)
			printf("%d ",g[i][j]);
		printf("\n");
	}
	return 0;
} 

1357 机器人搬东西

题目描述:
机器人移动学会(RMI)现在正尝试用机器人搬运物品。机器人的形状是一个直径1.6米的球。在试验阶段,机器人被用于在一个储藏室中搬运货物。储藏室是一个NxM的网格,有些格子为不可移动的障碍。机器人的中心总是在格点上,当然,机器人必须在最短的时间内把物品搬运到指定的地方。机器人接受的指令有:
·向前移动1步( creep ) ;
·向前移动2步( Walk ) ;
·向前移动3步(Run ) ;
·向左转(Left ) ;
·向右转(Right ) 。
每个指令所需要的时间为1秒。请你计算一下机器人完成任务所需的最少时间。

输入:
第一行为两个正整数N,M(1< N,M≤50),下面N行是储藏室的构造,0表示无障碍,1表示有障碍,数字之间用一个空格隔开。
接着一行有4个整数和1个大写字母,分别为起始点和目标点左上角网格的行与列,起始时的面对方向(东E,南S,西M,北N),数与数,数与字母之间均用一个空格隔开。终点的面向方向是任意的。

输出
一个整数,表示机器人完成任务所需的最少时间。如果无法到达,输出一1。

#include<iostream>
using namespace std;
bool a[55][55];
bool aa[55][55][4];
int b[10000][4];
int n,m,x0,y0,x1,y1;
int step=1,flag=0;
char c;
int frot=0,rear=1;
int turn(int u, bool lr)
{
    if(lr==0)
    {
        if(u==0) return 3;
        else return u-1;
    }
    else
    {
        if(u==3) return 0;
        else return u+1;
    }
}
void bfs()
{
    int i,x,y,d,step;
    while(frot < rear)
    {
        x = b[frot][0],y = b[frot][1],d = b[frot][2],step = b[frot][3];
        if(x==x1 && y==y1)
        {
            cout << b[frot][3];
            return;
        }
        if(aa[x][y][turn(d,0)]==0){
            aa[x][y][turn(d,0)]=1;
            b[rear][0]=x;
            b[rear][1]=y;
            b[rear][2]=turn(d,0);
            b[rear++][3]=step+1;
        }
        if(aa[x][y][turn(d,1)]==0){
            aa[x][y][turn(d,1)]=1;
            b[rear][0]=x;
            b[rear][1]=y;
            b[rear][2]=turn(d,1);
            b[rear++][3]=step+1;
        }
        for(i=1;i<=3;i++){
            if(d==0 && aa[x-i][y][d]==0 && a[x-1][y]==0 && a[x-i][y]==0 && x-i>0){
                aa[x-i][y][d]=1;
                b[rear][0]=x-i;
                b[rear][1]=y;
                b[rear][2]=d;
                b[rear++][3]=step+1;
            }
            if(d==2 && aa[x+i][y][d]==0 && a[x+1][y]==0 && a[x+i][y]==0 && x+i<n){
                aa[x+i][y][d]=1;
                b[rear][0]=x+i;
                b[rear][1]=y;
                b[rear][2]=d;
                b[rear++][3]=step+1;
            }
            if(d==3 && aa[x][y-i][d]==0 && a[x][y-1]==0 && a[x][y-i]==0 && y-i>0){
                aa[x][y-i][d]=1;
                b[rear][0]=x;
                b[rear][1]=y-i;
                b[rear][2]=d;
                b[rear++][3]=step+1;
            }
            if(d==1 && aa[x][y+i][d]==0 && a[x][y+1]==0 && a[x][y+i]==0 && y+i<m){
                aa[x][y+i][d]=1;
                b[rear][0]=x;
                b[rear][1]=y+i;
                b[rear][2]=d;
                b[rear++][3]=step+1;
            }
        }
        frot++;
    }
    cout << -1;
}
int main()
{
    int i,j,d,t;
    cin>>n>>m;
    for(i=1;i<=n;i++)
        for(j=1;j<=m;j++){
            cin>>t;
            if(t==1)
                a[i][j] = a[i-1][j] = a[i][j-1] = a[i-1][j-1] = 1;
        }
    cin >> x0 >> y0 >> x1 >> y1 >> c;
    if(c=='N') d = 0;
    else if(c=='E') d = 1;
    else if(c=='S') d = 2;
    else d = 3;
    aa[x0][y0][d] = 1;
    b[0][0] = x0,b[0][1] = y0, b[0][2] = d, b[0][3] = 0;
    bfs();
    return 0;
}


1358 取火柴

题目描述:
输入k及k个整数n1 ,n2 … ,nk,表示有k堆火柴棒,第i堆火柴棒的根数为n;接着便是你和计算机取火柴棒的对弈游戏。取的规则如下:每次可以从一堆中取走若干根火柴,也可以一堆全部取走,但不允许跨堆取,也不允许不取。

谁取走最后一根火柴为胜利者。

例如: k = 2,n1= n2= 2,A代表你,Р代表计算机,若决定A先取:
· A:(2,2)→(1,2),即从第一堆中取一根。
· P: (1,2) →(1,1),即从第二堆中取一根。
. A: (1,1)→ (1,0)。
. P: (1,0)→(0,0)。P胜利。

如果决定A后取:
· P: (2,2)→(2,0)。
·A: (2,0) →(0,0)。A胜利。

又如k = 3,n1 = 1,n2= 2,n3= 3,A决定后取:
.P: (1,2,3)→(0,2,3)。
. A: (0,2,3)→(0,2,2)。
·A已将游戏归结为(2,2)的情况,不管Р如何取A都必胜。

编一个程序,在给出初始状态之后,判断是先取必胜还是先取必败,如果是先取必胜,请输出第一次该如何取。如果是先取必败,则输出lose。

输入:
第一行,一个正整数k。
第二行,k个整数n1, n2,". ,nk。

输出
如果是先取必胜,请在第一行输出两个整数a,b,表示第一次从第b堆取出α个。第二行为第一次取火柴后的状态。如果有多种答案,则输出(b,a)字典序最小的答案(即b最小的前提下,使α最小)。

如果是先取必败,则输出(lose]。

#include<cstdio>
int k,n[500002];
int main()
{
    scanf("%d",&k);int x=0;
    for(int i=1;i<=k;i++)
    {
        scanf("%d",&n[i]);
        x^=n[i];
    }
    if(!x){puts("lose");return 0;}
    for(int i=1;i<=k;i++)
    {
        if((n[i]^x)>=n[i]) continue;
        printf("%d %d\n",(n[i]-(n[i]^x)),i);
        n[i]=n[i]^x;
        break;
    }
    for(int i=1;i<=k;i++)
    printf("%d ",n[i]);
}

1359 数字标记

题目描述:
赵拿到了一个数组,每个数字被染成了红色或蓝色。
赵有很多次操作,每次操作可以选择两个相邻的不同颜色的数字标记,并获得它们数字之和的得分。已经被标记的数字无法再次标记。
赵想知道,自己最多能获得多少分。

输入:
第一行输入一个正整数n ,代表数组的长度。
第二行输入n个正整数ai,代表赵拿到的数组。
第三行输入一个仅包含 'R′和’B’的字符串,第主个字符为’R′代表数组第i个数被染成红色,'B’代表被染成蓝色。
1 ≤n≤1e5
1≤a≤1e9

输出
输出一个整数,表示赵最多能获得的分值。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;

int a[N];
char b[N];
long long c[N];
int n;

int main()
{

    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    cin >> b+1;
    for (int i = 2; i <= n; i++)
    {
        if (b[i] == b[i-1])
            c[i] = c[i-1];
        else if (b[i] != b[i-1])
           c[i] = max(c[i-1], c[i-2]+a[i]+a[i-1]);
    }
    cout << c[n];
    return 0;
}

1360 环形字符串

题目描述:
赵拿到了一个环形字符串s。所谓环形字符串,指首尾相接的字符串。
赵想顺时针截取其中一段连续子串正好等于t,一共有多少种截法?

输入:
第一行输入字符串 s。
第二行输入字符串 t。
1 <len(t) ≤ len(s)≤1000

输出
环形字符串s截取一段连续子串等于字符串t 的方案数。

#include<bits/stdc++.h>

using namespace std;

int main(){
    
    string s;
    cin>>s;
    string v;
    cin>>v;
    
    map<int,int> sa;
    
    int cnt=0;
    
    string k=s+s;
    
    bool op=true;
    for(int i=0;i<k.size() && i<=s.size()-1;i++){
        op=true;
        int  l=i;
        for(int j=0;j<v.size();j++,l++){
            if(k[l]!=v[j]){
                op=false ;
                break;
            }
        }
        
        if(op) cnt++;
    }
    
    
    cout<<cnt;

    return 0;
}

1361 俄罗斯方块(easy)

题目描述:
小红正在玩一个奇怪的俄罗斯方块游戏。已知这个俄罗斯方块只有以下一种图形:
在这里插入图片描述

这个图形可以顺时针不旋转,旋转90度、180度、270度,分别变成以下四种情况:

在这里插入图片描述

当图形无法下落的时候,会停住不动。 请注意,这个俄罗斯方块没有消除的情况。也就是说会越累积越高。假设游戏共有8列,高度是无限的。请你输出最终每—列的高度。

输入:
第一行输入方块的数量n。
接下来的n 行,每行输入两个正整数α和 b,分别代表方块旋转的角度以及从哪一列下落的。方块是顺序下落的,也就是说前一个方块落到底之前,后一个方块不会开始下落。
1 ≤n ≤100
一定是0、90、180、270四个中的一个,b 代表方块的左端那一列,保证右端不会超过8。也就是说,若a为0或180,1 ≤ b ≤7;若a为90或270,1≤b≤6

输出
输出8个正整数,分别代表最终8列的高度。

#include<bits/stdc++.h>

using namespace std;
const int lp=1e3;

int c[lp];

int main(){
    
    int n;
    cin>>n;
    
    for(int i=1;i<=n;i++){
        int x,y;
        cin>>x>>y;
        if(!x){
            c[y]=max(c[y]+3,c[y+1]+3);
            c[y+1]=c[y]-2;
        }
        else if(x==90){
            c[y]=max(c[y]+2,max(c[y+1]+1,c[y+2]+1));
            c[y+1]=c[y+2]=c[y];
        }
        else if(x==180){
            c[y]=max(c[y]+1,c[y+1]+3);
            c[y+1]=c[y];
        }
        else {
            c[y]=max(c[y]+1,max(c[y+1]+1,c[y+2]+1));
            c[y+1]=c[y+2]=c[y];
            c[y+2]+=1;
        }
    }
    
    for(int i=1;i<=8;i++) cout<<c[i]<< ' ';
    
    
    return 0;
}

1362 打怪兽

题目描述:
  已知地图上有n 只怪物,每只怪物的血量是a,攻击力是bj。小红准备去地图上探险杀怪,她的初始血量为h。
  小红有两个技能:
  1.普通攻击:对—只怪物造成1点伤害。
  2.强力攻击:对一只怪物造成2点伤害。
  但是强力攻击是有冷却时间的。释放一个强力攻击后,需要2回合冷却(即释放2次普通攻击后)才能再次释放。
  小红每次攻击后,若怪物没有死亡(即血量大于0),小红都会承受一次怪物攻击力的伤害。但是小红可以在战斗开始前喝血药,每个血药可以回复k点血量。也就算说,α瓶血药可以将小红的初始血量提高到h +a * k
  已知每只怪物都是不可复活的,当小红血量为0或负数时死亡。小红选择打一个怪时,在该怪物被打死之前不会更换目标。
  当小红打死一只怪物去寻找另外一只怪物的过程中,我们可以认为强力攻击的冷却已经恢复完毕。请问,小红初始带了α瓶血药时,最多可以击杀多少只怪物?
上述问题会重复q次,每次询问都是独立的,小红初始的血瓶数量可能不同。

输入:
  第一行输入三个正整数 n, h, k ,代表地图上怪物的数量、小红的初始血量,以及小红每瓶血药可以回复的血量。
  接下来的n 行,每行输入两个正整数ai和 bi,代表地图上每只怪物的血量和攻击力。接下来的一行输入一个正整数q,代表询问次数。
  接下来的一行,输入q个正整数c,代表每次询问中小红携带的血药数量。1 ≤n, q, h, k, ai, bi, a ≤105

输出
输出一行q个正整数,代表小红携带α 瓶血药时能击杀的最多怪物数量。

#include<bits/stdc++.h>
#define int long long

using namespace std;
const int lp=1e5+10;

long long sum[lp];
vector< pair<int,int> > c;

signed main(){
    
    int n,k,h;
    cin>>n>>h>>k;
    
    for(int i=1;i<=n;i++){
        int x,y;
        cin>>x>>y;
        
        int cnt=x%4;
        int p=x/4*3;
        
        if(cnt) p+=(cnt<=2 ? 1:2);
        int pa=(p-1)*y;
        c.push_back({pa,p});
    }
    
    sort(c.begin(),c.end());
    
    int o=1;
    for(auto x:c){
        sum[o]=sum[o-1]+x.first;
        o++;
    }

    int q;
    cin>>q;
    for(;q;q--){
        int x;
        cin>>x;
        
        int u=h+x*k;
        
        if(u<sum[1]){
            cout<<0<<' ';
            continue;
        }
        
        int l=1,r=o;
        while(l+1!=r){
            int mid=l+r>>1;
            if(sum[mid] < u ) l=mid;
            else r=mid;
        }
        cout<<l<<' ';
        
    }
    
    return 0;
}

1363 孙宁的数组操作

题目描述:
本题保证 x = 1。
孙宁拿到了一个数组,她可以进行若干次以下操作:
1.选择一个元素,花费p,使其加x。
2.选择一个元素,花费q,使其减y。
小红希望若干次操作后,数组的平均数是一个整数。你能帮小红求出最小的总代价吗?

输入:
第一行输入五个正整数n, p, x, q, y。n代表数组的大小,其余几个变量如题目描述所示。
第二行输入n个正整数ai,代表数组的元素。
1≤ n ≤1e5
x= 1
1≤ai, y, p, q ≤1e9

输出
如果无解,请输出-1。
否则输出一个整数,代表最小的总代价。

#include<bits/stdc++.h>
using namespace std;
#define int long long
int a[202020];
signed main(){
    int n,p,x,q,y,i;
    cin>>n>>p>>x>>q>>y;
    int s=0;
    for(i=0;i<n;i++)cin>>a[i],s+=a[i];
    s%=n;
    int mi=1e18;
    for(i=0;i<n;i++){
        mi=min(mi,((n-(s-i*y)%n+n)%n)%n*p+q*i);
    }
    cout<<mi;
}


1364 以撒和隐藏房间

题目描述:
  以撒逃进了地下室:
  地下室可以看作一个n*m的矩阵的迷宫,其中有些格子是有门相连房间,有些则是无法通过的墙壁。以撒发现其中一些墙壁似乎是空心的,可以通过爆炸打开隐藏的房间,而隐藏房的生成有一定的规律,以撒认为一个墙壁格子在满足以下所有情况时可能会是隐藏房间:
  1,该墙壁格子和三个普通房间相邻
  2,在满足1条件的情况下,不能和boss房间相邻但是以撒正在和萌死戳交战,
  现在你需要编写程序告诉他是否存在可能是隐藏房间的格子。
  如果存在,输出两行,第一行是一个YES,第二行输出可能为隐藏房间的格子的数量如果不存在,输出NO

输入:
 第一行两个整数n,m ( 3<m,n<=1000)
 然后是一个n*m矩阵,表示地图状态,o表示墙壁,1表示房间,2表示boss房间

输出
 如果存在,输出两行,第一行是一个YES,第二行输出可能为隐藏房间的格子的数量如果不存在,输出NO

#include <iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long ll;
const int N = 1005;
int n,m; 
char mp[N][N];
bool check(int x,int y){
	return (x<=n&&x>=1&&y<=m&&y>=1)?1:0;
}
int mv[2][4]={{1,-1,0,0},{0,0,1,-1}};
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++){
    	for(int j=1;j<=m;j++){
    		cin>>mp[i][j];
		}
	}
	int ans=0;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(mp[i][j]!='0')continue;
			int num=0,f=0;
			for(int k=0;k<4;k++){
				int x=mv[0][k]+i,y=mv[1][k]+j;
				if(!check(x,y))continue;
				if(mp[x][y]=='1'){
					num++;
				}
				if(mp[x][y]=='2'){
					f=1;
				}
				
			}
//			cout<<num<<endl;
			if(num==3&&!f)ans++;
		}
	}
	if(ans==0)cout<<"NO";
	else cout<<"YES\n"<<ans;
    return 0;
}

1365 合唱比赛

题目描述:
 河南农业大学信管学院举办一年一度的合唱比赛,目前你是评委之一,剩下还有其他的n位评委,给定一个正整数n和n个正整数表示这n个评委给目前在表演的团队的分数,评分规则为在所有评委(包括你)的分数中去掉一个最高分和最低分,剩下的取平均值(总共n-1个值),现在你可以参与评分(1~100之间的整数),问最终结果会在什么区间内,用两个数表示这个区间,结果保留6位小数。

输入:
第一行给定一个正整数n
接下来一行给定n个整数表示n个评委的分数
2<=n<=1000

输出
输出两个保留六位的小数l,r表示答案。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int main()
{
    int n;
    cin>>n;
    double ans1=100,ans2=0;
    vector<int>vc(n+1);
    for(int i=1;i<=n;i++)cin>>vc[i];
    for(int i=1;i<=100;i++)
    {
        ll sum=0;
        vc[0]=i;
        for(int j=0;j<=n;j++)sum+=vc[j];
        sum-=(*min_element(vc.begin(),vc.end()));
        sum-=(*max_element(vc.begin(),vc.end()));
        ans1=min(ans1,sum*1.0/(n-1));
        ans2=max(ans2,sum*1.0/(n-1));
    }
    printf("%.6lf %.6lf\n",ans1,ans2);
}

1366 动物朋友

题目描述:
 已知有n个动物朋友排成一排,每个动物朋友都有一个正整数的快乐值,涛涛每次会和连续的动物朋友玩,并且获得这些动物朋友快乐值的和的快乐,而涛涛是个完美主义者,他觉得快乐值刚好是m时候才是快乐的,现在请问有多少种选择方式,使得所选的连续的动物朋友的快乐值刚好为m。

输入:
 第一行输入n (1<=n<=1e6)和m ( 1<=m<=1e6)。
 第二行输入n个正整数,第i个代表第i个动物朋友的快乐值。(1<=ai<=1e5)

输出
 一个整数,表示可能存在的选法数量,如果没有,就输出0;

#include <iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long ll;
 
const int N = 1000005;

int n,m; int v[N];
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>v[i];
	}
	int now=0,cnt=0;
	for(int i=1,j=0;i<=n&&j<=n;){ 
		 if(now<m&&j<n){
		 	now+=v[++j];
		 	continue;
		 }
		 if(now>m&&i<n){
		 	now-=v[i++];
		 	continue;
		 }
		 if(now==m)cnt++;
		 now+=v[++j];
	}
	cout<<cnt<<endl;
    return 0;
}
 

1367 松鼠排序

题目描述:
 松鼠宝宝有一排n个大小不一的坚果,松鼠宝宝想把坚果从小到大排序,每次他会选择两个坚果a和b每次花费1点力气把这两个坚果交换,爱动脑筋的松鼠宝宝想知道他排完这n个坚果一共需要花费的最少力气是多少?

输入:
第一行一个整数n代表坚果数
接下来一行n个整数代表每个坚果的大小(每个坚果大小都不一样,即大小为1-n的一个排列)1<=n<=1e5
坚果大小x,1<=x<=n

输出
一行输出代表松鼠宝宝花费的最小力气

#include <bits/stdc++.h>

using namespace std;

const int maxn = 1e6 + 10;

int a[maxn], b[maxn], p[maxn];

int find(int x) {
    if (x != p[x]) p[x] = find(p[x]);
    return p[x];
}

int main() {
    int n;
    cin >> n;
    for (int i = 0; i <= n; i ++ ) {
        p[i] = i;
        b[i] = i;
    }
    for (int i = 1; i <= n; i ++ ) {
        cin >> a[i];
    }
    for (int i = 1; i <= n; i ++ ) {
        if (a[i] != b[i]) {
            int aa = find(a[i]);
            int bb = find(b[i]);
            if (aa != bb) {
                p[aa] = bb;
            }
        }
    }
    unordered_map<int, int> mp;
    for (int i = 1; i <= n; i ++ ) {
        mp[find(i)] ++;
    }
    int ans = n - mp.size();
    cout << ans << '\n';
}

1368 Reverse

题目描述:
给定一个长度为n的01串,你需要选择一段任意长度(可以为0)的区间对其翻转,翻转后,求最长的一段连续的全是1的区间的长度

输入:
输入共2行。
第一行一个整数n(1≤n ≤106)。第二行一个长度为n的01序列。

输出
输出一个整数,表示最长的长度

#include<iostream>
#include<vector>
#include<algorithm>

using namespace std;

int n;
char s[1000010];

int main() {
    scanf("%d%s", &n, s);
    vector<int> a;
    int l = 0;
    while(l < n) {
        if(s[l] == '0') l++;
        else {
            int j = l;
            while(j + 1 < n && s[j + 1] == '1') j++;
            a.push_back(j - l + 1);
            l = j + 1;
        }
    }
    sort(a.begin(), a.end());
    int m = a.size();
    if(m == 0) cout << 0;
    else if(m == 1) cout << a[0];
    else cout << a[m - 1] + a[m - 2];
    return 0;
}

1369 迷宫探险

题目描述:
 在与boss的最终决战之后,小蓝来到了冒险的最后一关,在他面前有一个n*m的迷宫,迷宫中道路用 . 表示,墙壁则由 # 表示。小蓝初始在[1,1]的位置,他只有到达[n,m]才能开启最终的宝藏。小蓝现在迫不及待的想要开启宝藏,所以他想最短的时间内走出迷宫。现在迷宫内有一种特殊的装置–弹射器”。弹射器的格子用 * 表示。当走到有弹射器的一格时,小蓝必须选择一个方向,弹射器会让他沿着这个方向弹射x个距离,不同弹射器的弹射距离可以不同。弹射后的格子如果超过迷宫边界或者是墙壁则不能选择这个方向。小蓝现在可以向上下左右四个方向走,每走一个格子需要消耗一个单位时间,弹射则不消耗时间。求最短需要多少时间小蓝才能走出迷宫。如果无法到达终点,输出-1。
弹射器的数量,位置和弹射距离将在输入中给出。起点和终点一定不是弹射器。

输入:
第一行两个整数n, m,接下来n行,每行m个只包含’.’,’”,'#'的字符描绘迷宫。
接下来一行一个整数k,下面的k行每行三个整数x, y, w表示在[x, y]格子的弹射器能弹射的距离。( 2≤n≤3000 ,2≤m≤3000, n
m≤500000,0≤k , w在int范围内)

输出
一行一个整数

#include<bits/stdc++.h>
using namespace std;

int n, m;
queue<pair<int, int>>q;
int dx[] = {1, -1, 0, 0};
int dy[] = {0, 0, 1, -1};
map<pair<int,int>, int>mp;

//void bfs()
//{
//	q.push({1, 1});
//	dis[1][1] = 0;
//	while( !q.empty() )
//	{
//		int x = q.front().first;
//		int y = q.front().second;
		cout << x << ' ' << y << s[x][y] << '\n';
//		q.pop();
//		if( x == n && y == m ) continue;
//		if( s[x][y] == '*' ) 
//		{
//			for( int i = 0 ; i < 4 ; i++ )
//			{
//				int xx = x + dx[i]*mp[{x, y}];
//				int yy = y + dy[i]*mp[{x, y}];
//				
//				if( xx <= 0 || yy <= 0 || xx > n || yy > m || s[xx][yy] == '#' ) continue;
//				
//				dis[xx][yy] = min(dis[x][y], dis[xx][yy]);
//				
//				q.push({xx, yy});
//			}
//			continue;
//		}
//		
//		
//		for( int i = 0 ; i < 4 ; i++ )
//		{
//			int xx = x + dx[i];
//			int yy = y + dy[i];
			cout << i << '\n';
//			if( xx <= 0 || yy <= 0 || xx > n || yy > m || s[xx][yy] == '#' ) continue;
//			dis[xx][yy] = min( dis[xx][yy], dis[x][y] + 1 );
//			q.push({xx, yy});
//			
//		}
//	}
//	
//	if( dis[n][m] != INT_MAX ) cout << dis[n][m];
//	else cout << "-1" ;
//}
int main()
{
	cin >> n >> m;
	string s[n+1];
	for( int i = 1 ; i <= n ; i++ ) cin >> s[i];
	for( int i = 1 ; i <= n ; i++ ) s[i] = " " + s[i];
	
	vector< vector<int> > dis(n+1, vector<int>(m+1));
	 
	for( int i = 1 ; i <= n ; i++ )
		for( int j = 1 ; j <= m; j++ ) 
			dis[i][j] = 500000;
			
	int k;
	cin >> k;
	
	for( int i = 1; i <= k ; i++ )
	{
		int x, y, d; cin >> x >> y >> d;
		mp[{x, y}] = d;
	}
	
	q.push({1, 1});
	dis[1][1] = 0;
	while( !q.empty() )
	{
		int x = q.front().first;
		int y = q.front().second;
//		cout << x << ' ' << y << s[x][y] << '\n';
		q.pop();
		if( x == n && y == m ) continue;
		if( s[x][y] == '*' ) 
		{
			for( int i = 0 ; i < 4 ; i++ )
			{
				int xx = x + dx[i]*mp[{x, y}];
				int yy = y + dy[i]*mp[{x, y}];
				
				if( xx <= 0 || yy <= 0 || xx > n || yy > m || s[xx][yy] == '#' ) continue;
				if( dis[x][y] < dis[xx][yy] ) 
                {
                    dis[xx][yy] = min(dis[x][y], dis[xx][yy]);
				
				    q.push({xx, yy});
                }
				
			}
			continue;
		}
		
		
		for( int i = 0 ; i < 4 ; i++ )
		{
			int xx = x + dx[i];
			int yy = y + dy[i];
//			cout << i << '\n';
			if( xx <= 0 || yy <= 0 || xx > n || yy > m || s[xx][yy] == '#' ) continue;
            if( dis[x][y] + 1 < dis[xx][yy] ) 
            {
                dis[xx][yy] = dis[x][y] + 1;
			     q.push({xx, yy});
            }
			
			
		}
	}
	
	if( dis[n][m] != 500000) cout << dis[n][m];
	else cout << "-1" ;
}

1370 猜拳游戏

题目描述:

石头剪刀布
你输了总会哭
你说初一是一只可爱的小天狗
把月亮咬了一口
然后它就一直守
——《青梅竹马》
  你正在与长途玩石头剪刀布的猜拳游戏。 请回忆石头剪刀布的游戏规则:两个人同时伸出手,分别出示石头(用 shitou 表示)、剪刀(用 jiandao 表示)或布(用 bu 表示)的手势。石头胜剪刀,剪刀胜布,布胜石头。如果两个人出示的手 势相同,则是平局,需要重新进行游戏。 在开始游戏之前,长途会告诉你他要出石头、剪刀还是布。 然而实际上,长途是在欺骗你。他认为你会相信他的话,并且认为你一定会根据他说的话选择能战胜他 的手势(例如,他说他会出石头,他便认为你会出布)。 所以最终,长途不会按照他告诉你的手势出拳,而是选择自己所认为一定能战胜你的手势。 现在你已经看透了他的小心思。请问,在知道他告诉你他要出什么手势的情况下,你应该出什么手势才 能取胜?

输入:
仅 输 入 一 行 , 包 含 一 个 字 符 串 , 表 示 长 途 告 诉 你 的 他 要 出 的 手 势 。 保 证 字 符 串 一 定 是 shitou,jiandao,bu 中的一个。

输出
仅 输 出 一 行 , 包 含 一 个 字 符 串 , 表 示 最 终 你 能 取 胜 的 手 势 。 输 出 字 母 必须是小写

#include<bits/stdc++.h>

using namespace std;

int main(){
    
    string s;
    cin>>s;
    if(s=="bu") cout<<"bu";
    else if(s=="jiandao") cout<<"jiandao";
    else cout<<"shitou";
    cout<<endl;
    return 0;
}

1371 Kevin喜欢一

题目描述:
氧气少年 最近喜欢上了一。 氧气少年 有一个文本输入框,最初文本输入框里只有一个字符 ‘1’。 氧气少年 每次可以进行下面的操作:
• 选中文本输入框中的部分或全部字符,将选中的字符复制到剪贴板,然后立即将复制的内容粘贴 到文本输入框末尾。
现在 氧气少年 想让文本输入框中恰好有 n 个 ‘1’,请求出他需要做的最少的操作次数。

输入:
第一行包含一个整数 T(1 ≤ T ≤ 2 · 105 ),表示测试用例的组数。
对于每组测试用例: 仅输入一行,包含一个整数 n(1 ≤ n ≤ 109 )。

输出
对于每组测试用例: 仅输出一行,包含一个整数,表示答案。

#include<bits/stdc++.h>

using namespace std;

int main(){
    
    int t;
    cin>>t;
    
    while(t--){
        int n;
        cin>>n;
        
        if(n==1) cout<<0<<endl;
        else{
            int u=log2(n);
            
            if(log2(n)>u) cout<<u+1<<endl;
            else cout<<u<<endl;
        }
    }
    
    return 0;
}

1372 A加B,A模B

题目描述:
给出两个整数 n 和 m,请你找出两个整数 a 和 b,并且 a 和 b 需要同时满足以下条件:

  1. a + b = n
  2. a mod b = m
    • 0 ≤ a ≤ 109 , 1 ≤ b ≤ 109
    其中,mod 代表计算两个数相除后的余数,例如 10 mod 3 = 1, 4 mod 2 = 0。 如果找不到合法的 a 和 b,输出 −1;否则请输出你找到的 a 和 b。如果有多个可行的答案,请输出任意

输入:
第一行包含一个整数 T(1 ≤ T ≤ 2 · 105 ),表示测试用例的组数。
对于每组测试用例: 仅输入一行,包含两个整数 n, m (0 ≤ n, m ≤ 109 )。

输出
对于每组测试用例: 仅输出一行。如果找不到合法的 a 和 b,输出 −1;
否则请输出两个整数 a 和 b。如果有多个可行的答 案,请输出任意一个

#include<bits/stdc++.h>

using namespace std;

int main(){
    
    int t;
    cin>>t;
    
    while(t--){
        
        int n,m;
        cin>>n>>m;
        
        if(n<=2*m) cout<<-1<<endl;
        else cout<<m<<' '<<n-m<<endl;
        
    }
    
    return 0;
}

1373 MoonLight的运算问题

题目描述:
月色哥哥 手中有一个数字 x,最初 x = 0。 给出一个长度为 n 的序列 a,月色哥哥 会从序列的第一个元素 a1 按顺序看到序列的最后一个元素 an。 对于序列的第 i 个元素 ai,月色哥哥 可以进行下面的操作之一:
 • 令 x = x · ai;
 • 令 x = x + ai。
请求出 x 的最大值,并输出这个最大值除 998244353 的余数。

输入:
第一行包含一个整数 T(1 ≤ T ≤ 105 ),表示测试用例的组数。
对于每组测试用例: 第一行包含一个整数 n(1 ≤ n ≤ 2 · 105),表示序列的长度。
第二行包含 n 个整数 a1 . . . an(0 ≤ ai ≤ 109 ),表示该序列。
保证对于所有的测试用例,n 的总和不超过 2 · 105。

输出
对于每组测试用例: 仅输出一行,包含一个整数,表示答案。

#include<bits/stdc++.h>
#define int long long
using namespace std;

const int mod=998244353;

signed main(){
    
    int t;
    cin>>t;
    
    while(t--){
        int n;
        cin>>n;
        
        int x=0;
        int u=1;
        for(int i=1;i<=n;i++){
            int y;
           cin>>y;
            
            if(y<=1){
                x=x+y;
                x%=mod;            
            }
            else if(x<=1 && u){
                x=x+y;
                x%=mod;
                u=0;
            }
            else{
                x=x*y;
                x=x%mod;
            }
            
        }
        
        cout<<x<<endl;
        
    }
    
    
    return 0;
}

1374 括号序列操作专家

题目描述:
氧气少年 有一个长度为 n 的括号序列,括号序列只包含左括号 ‘(’ 和右括号 ‘)’。 一个括号序列是合法的,当且仅当此括号序列可以通过插入加号 ‘+’ 和数字 1 得到一个正确的算术表达 式。例如:括号序列 (())(),(),和 (()(())) 都是合法的,而 )(,(() 和 (()))( 不是合法的。 氧气少年 的括号序列不一定是合法的。 月色哥哥 是一个括号序列的操作专家,他的任务是帮助 氧气少年 把这个括号序列变成一个合法的序 列。
为了把这个括号序列变合法,月色哥哥 每次可以进行下面的操作:
• 交换任意两个相邻括号。
如果无论 月色哥哥 怎么操作都无法使括号序列变合法,输出 −1;否则请输出他需要做的最少的操作次 数。

输入:
第一行包含一个整数 T(1 ≤ T ≤ 105 ),表示测试用例的组数。
对于每组测试用例: 第一行包含一个整数 n(1 ≤ n ≤ 2 · 105 ),表示括号序列的长度。
第二行包含一个长度为 n 的字符串,表示该括号序列。
保证字符串只包含左括号 ‘(’ 和右括号 ‘)’。 保证对于所有的测试用例,n 的总和不超过 2 · 105。

输出
对于每组测试用例: 仅输出一行,包含一个整数。
如果无论怎么操作都无法使括号序列变合法,输出 −1;
否则请输出他需 要做的最少的操作次数。

#include<bits/stdc++.h>

using namespace std;

int main(){
    
    int t;
    cin>>t;
    
    while(t--){
        int n;
        cin>>n;
        
        string s;
        cin>>s;
        
        int u=0;
        for(int i=0;i<n;i++){
            if(s[i]=='(') u++;
        }
        
        if(u*2!=n) {
            cout<<-1<<endl;
            continue;
        }
        
        long long ans=0,l=0,r=0;
        for(int i=0;i<n;i++){
            if(s[i]=='('){
                if(r>0){
                    ans+=r;
                    r--;
                }
                else{
                    l++;
                }
            }
            else{
                if(l>0) l--;
                else r++;
            }
        }
        
        cout<<ans<<endl;
        
    }
    
    
    return 0;
}

1375 Vika and the Bridge

题目描述:
In the summer, Vika likes to visit her country house. There is everything for relaxation: comfortable swings, bicycles, and a river.

There is a wooden bridge over the river, consisting of n n n planks. It is quite old and unattractive, so Vika decided to paint it. And in the shed, they just found cans of paint of k k k colors.

After painting each plank in one of k k k colors, Vika was about to go swinging to take a break from work. However, she realized that the house was on the other side of the river, and the paint had not yet completely dried, so she could not walk on the bridge yet.

In order not to spoil the appearance of the bridge, Vika decided that she would still walk on it, but only stepping on planks of the same color. Otherwise, a small layer of paint on her sole will spoil the plank of another color. Vika also has a little paint left, but it will only be enough to repaint one plank of the bridge.

Now Vika is standing on the ground in front of the first plank. To walk across the bridge, she will choose some planks of the same color (after repainting), which have numbers 1 ≤ i 1 < i 2 < … < i m ≤ n 1 \le i_1 < i_2 < \ldots < i_m \le n 1i1<i2<<imn (planks are numbered from 1 1 1 from left to right). Then Vika will have to cross i 1 − 1 , i 2 − i 1 − 1 , i 3 − i 2 − 1 , … , i m − i m − 1 − 1 , n − i m i_1 - 1, i_2 - i_1 - 1, i_3 - i_2 - 1, \ldots, i_m - i_{m-1} - 1, n - i_m i11,i2i11,i3i21,,imim11,nim planks as a result of each of m + 1 m + 1 m+1 steps.

Since Vika is afraid of falling, she does not want to take too long steps. Help her and tell her the minimum possible maximum number of planks she will have to cross in one step, if she can repaint one (or zero) plank a different color while crossing the bridge.

输入:
  Each test consists of multiple test cases. The first line contains a single integer t t t ( 1 ≤ t ≤ 1 0 4 1 \le t \le 10^4 1t104) — the number of test cases. The description of the test cases follows.
  The first line of each test case contains two integers n n n and k k k ( 1 ≤ k ≤ n ≤ 2 ⋅ 1 0 5 1 \le k \le n \le 2 \cdot 10^5 1kn2105) — the number of planks in the bridge and the number of different colors of paint.
  The second line of each test case contains n n n integers c 1 , c 2 , c 3 , … , c n c_1, c_2, c_3, \dots, c_n c1,c2,c3,,cn ( 1 ≤ c i ≤ k 1 \le c_i \le k 1cik) — the colors in which Vika painted the planks of the bridge.
 It is guaranteed that the sum of n n n over all test cases does not exceed 2 ⋅ 1 0 5 2 \cdot 10^5 2105.

输出
For each test case, output a single integer — the minimum possible maximum number of planks that Vika will have to step over in one step.


1376 Vika and Her Friends

题目描述:
Vika and her friends went shopping in a mall, which can be represented as a rectangular grid of rooms with sides of length n n n and m m m. Each room has coordinates ( a , b ) (a, b) (a,b), where 1 ≤ a ≤ n , 1 ≤ b ≤ m 1 \le a \le n, 1 \le b \le m 1an,1bm. Thus we call a hall with coordinates ( c , d ) (c, d) (c,d) a neighbouring for it if ∣ a − c ∣ + ∣ b − d ∣ = 1 |a - c| + |b - d| = 1 ac+bd=1.

Tired of empty fashion talks, Vika decided to sneak away unnoticed. But since she hasn’t had a chance to visit one of the shops yet, she doesn’t want to leave the mall. After a while, her friends noticed Vika’s disappearance and started looking for her.

Currently, Vika is in a room with coordinates (x, y), and her k friends are in rooms with coordinates (x_1, y_1), (x_2, y_2), … , (x_k, y_k), respectively. The coordinates can coincide. Note that all the girls must move to the neighbouring rooms.

Every minute, first Vika moves to one of the adjacent to the side rooms of her choice, and then each friend (seeing Vika’s choice) also chooses one of the adjacent rooms to move to.

If at the end of the minute (that is, after all the girls have moved on to the neighbouring rooms) at least one friend is in the same room as Vika, she is caught and all the other friends are called.

Tell us, can Vika run away from her annoying friends forever, or will she have to continue listening to empty fashion talks after some time?

输入:
Each test consists of multiple test cases. The first line contains a single integer t t t ( 1 ≤ t ≤ 100 1 \le t \le 100 1t100) — the number of test cases. The description of the test cases follows.

The first line of each test case contains three integers n n n, m m m, k k k ( 1 ≤ n , m , k ≤ 100 1 \le n, m, k \le 100 1n,m,k100) — the sizes of the mall and the number of Vika’s friends.

The second line of each test case contains a pair of integers x x x and y y y ( 1 ≤ x ≤ n 1 \le x \le n 1xn, 1 ≤ y ≤ m 1 \le y \le m 1ym) — the coordinates of the room where Vika is.

Each of the next k k k lines of each test case contains a pair of integers x i x_i xi and y i y_i yi ( 1 ≤ x i ≤ n 1 \le x_i \le n 1xin, 1 ≤ y i ≤ m 1 \le y_i \le m 1yim) — the coordinates of the room where the i i i-th friend is.

输出
For each test case, output “YES” if Vika can run away from her friends forever, otherwise output “NO”.

#include<iostream>

using namespace std;

int main(){
	
	int t;
	cin>>t;
	
	while(t--){
		int n,m,k;
		cin>>n>>m>>k;
		int x,y;
		cin>>x>>y;
		
		bool end=true;
		for(int i=1;i<=k;i++){
			int u,p;
			cin>>u>>p;
			if((abs(x-u)+abs(p-y)-1) & 1 ) end=false;
		}
		
		if(!end) cout<<"NO";
		else cout<<"YES";
		cout<<endl;
		
	}
	
	
	return 0;
} 

1377 Hide-And-Seek Game

题目描述:
  During the summer vacation, Serenade and Rhapsody are playing hide-and-seek in a park structured as a tree. Each edge of the tree has a weight of 1. Serenade keeps running back and forth between Sa and Ta (Sa ≠ Ta), while Rhapsody runs back and forth between Sb and Tb (Sb ≠ Tb). However, Aria doesn’t want to run around with them and only wants to know the earliest location where Serenade and Rhapsody will meet. Please output the identification number of this location.If they will never meet, output -1.
  To be more specific, Serenade starts from Sa and moves one edge towards Ta each time. Once reaching Ta, Serenade then moves one edge towards Sa each time. After reaching Sa, Serenade moves one edge towards Ta each time, and so on. Rhapsody follows a similar pattern of movement.
  Note that this park is quite mysterious, so Serenade and Rhapsody will not meet on an edge (you can assume that they will choose different paths to traverse the same edge).

输入:
  The input consists of multiple test cases. The first line contains a single integer t(1 ≤ t ≤ 500) — the number of test cases. Description of the test cases follows
   The first line of each test case contains two integers n and m (2 ≤ n, m ≤ 3 · 103 ) — the number of the vertices in the given tree and the number of questions.
   Each of the next n − 1 lines contains two integers u and v (1 ≤ u, v ≤ n, u ≠ v) meaning that there is an edge between vertices u and v in the tree.
  Each of the next m lines contains four integers Sa , Ta , Sb and Tb (1 ≤ Sa, Ta, Sb, Tb ≤ n, Sa ≠ Ta and Sb ≠ Tb) .
   It is guaranteed that the given graph is a tree.
  The data guarantees that there will be no more than 20 groups with a value of n exceeding 400.
  The data guarantees that there will be no more than 20 groups with a value of m exceeding 400

输出
For each test case print a single integer — the identification number of this location which Serenade and Rhapsody will meet or -1

#include<cstdio>
#include<algorithm>
#include<cmath>
#define M 5005
using namespace std;
struct E{
	int to,nx;
}edge[M<<1];
int tot,head[M];
void Addedge(int a,int b){
	edge[++tot].to=b;
	edge[tot].nx=head[a];
	head[a]=tot;
}
int sz[M],son[M],top[M],dep[M];
int Dfn[M],Low[M],tot_dfs;
int fa[M];
void dfs(int now){
	Dfn[now]=++tot_dfs;
	sz[now]=1;son[now]=0;
	for(int i=head[now];i;i=edge[i].nx){
		int nxt=edge[i].to;
		if(nxt==fa[now])continue;
		fa[nxt]=now;
		dep[nxt]=dep[now]+1;
		dfs(nxt);
		sz[now]+=sz[nxt];
		if(sz[son[now]]<sz[nxt])son[now]=nxt;
	}
	Low[now]=tot_dfs;
}
void dfs_top(int now){
	if(son[now]){
		top[son[now]]=top[now];
		dfs_top(son[now]);
	}
	for(int i=head[now];i;i=edge[i].nx){
		int nxt=edge[i].to;
		if(nxt==fa[now]||nxt==son[now])continue;
		top[nxt]=nxt;
		dfs_top(nxt);
	}
}
int LCA(int a,int b){
	while(top[a]!=top[b]){
		if(dep[top[a]]<dep[top[b]])b=fa[top[b]];
		else a=fa[top[a]];
	}
	return dep[a]<dep[b]?a:b;
}
bool In(int x,int y){
	return Dfn[y]<=Dfn[x]&&Dfn[x]<=Low[y];
}
int mark[M];
struct Point{
	int a,b;
};
Point Data[M][2];
int exgcd(int a,int b,int &x,int &y){
	int d=a; if(b==0) x=1,y=0; else{
		d=exgcd(b,a%b,y,x),y-=a/b*x;
	}
	return d;
}
int Get_ans(Point p1,Point p2){
	int val=p2.b-p1.b;
	val%=p2.a;
	while(val<0)val+=p2.a;
	while(val>p2.a)val-=p2.a;
	int a=p1.a,b=-p2.a;
	int x,y,d=exgcd(a,b,x,y);
	if(val%d!=0)return 1e9;
	x*=val/d;y*=val/d;
	int p=b/d,q=a/d;
	if(x<0){
		int k=ceil((1.0-x)/p);
		x+=p*k,y-=q*k;
	}else if(x>=0){
		int k=(x-1)/p;
		x-=p*k,y+=q*k;
	}
	return a*x+p1.b;
}
int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		int n,m;
		tot=0;
		scanf("%d%d",&n,&m);
		tot_dfs=0;
		for(int i=1;i<=n;i++)head[i]=mark[i]=0;
		for(int i=1;i<n;i++){
			int a,b;
			scanf("%d%d",&a,&b);
			Addedge(a,b);
			Addedge(b,a);
		}
		dfs(1);
		top[1]=1;
		dfs_top(1);
		for(int step=1;step<=m;step++){
			int a,b,c,d;
			scanf("%d%d%d%d",&a,&b,&c,&d);
			if(a==c){printf("%d\n",a);continue;}
			int x1=LCA(a,b),x2=LCA(c,d);
			if(dep[x1]>dep[x2]){
				swap(a,c);
				swap(b,d);
				swap(x1,x2);
			}
			if(!In(a,x2)&&!In(b,x2)){
				puts("-1");
				continue;
			}
			int d1=dep[a]+dep[b]-2*dep[x1],d2=dep[c]+dep[d]-2*dep[x2];
			int p=a;
			while(1){
				Data[p][0]=(Point){2*d1,dep[a]-dep[p]};
				Data[p][1]=(Point){2*d1,2*d1-(dep[a]-dep[p])};
				mark[p]=step;
				if(p==x1)break;
				p=fa[p];
			}
			p=b;
			while(p!=x1){
				Data[p][0]=(Point){2*d1,d1-(dep[b]-dep[p])};
				Data[p][1]=(Point){2*d1,d1+(dep[b]-dep[p])};
				mark[p]=step;
				p=fa[p];
			}
			
			int ans_val=1e9,ans=-1;
			p=c;
			while(1){
				Point p1=(Point){2*d2,dep[c]-dep[p]};
				Point p2=(Point){2*d2,2*d2-(dep[c]-dep[p])};
				if(mark[p]==step){
					int res=1e9;
					res=min(min(Get_ans(p1,Data[p][0]),Get_ans(p1,Data[p][1])),min(Get_ans(p2,Data[p][0]),Get_ans(p2,Data[p][1])));
					if(res<ans_val){
						ans_val=res;
						ans=p;
					}
				}
				if(p==x2)break;
				p=fa[p];
			}
			p=d;
			while(p!=x2){
				Point p1=(Point){2*d2,d2-(dep[d]-dep[p])};
				Point p2=(Point){2*d2,d2+(dep[d]-dep[p])};
				if(mark[p]==step){
					int res=1e9;
					res=min(min(Get_ans(p1,Data[p][0]),Get_ans(p1,Data[p][1])),min(Get_ans(p2,Data[p][0]),Get_ans(p2,Data[p][1])));
					if(res<ans_val){
						ans_val=res;
						ans=p;
					}
				}
				p=fa[p];
			}
			printf("%d\n",ans);
		}
	}
	return 0;
}

1378 City Upgrading

题目描述:
The city where crazyzhk resides is structured as a tree. On a certain day, the city’s network needs to be upgraded. To achieve this goal, routers need to be deployed. Each router covers the node it is placed on and its neighboring nodes. There is a cost ai associated with placing a router at each node. The question is: How can the routers be deployed at minimum cost to ensure that every node is covered?

输入:
  The input consists of multiple test cases. The first line contains a single integer t(1 ≤ t ≤ 1000) — the number of test cases. Description of the test cases follows.
  The first line of each test case contains a integer n (1 ≤ n ≤ 105 ) — the number of the vertices in the given tree.
  The second line of each case are n integers ai (1 ≤ ai ≤ 105 ),denoting the cost of setting up a router at each node.
  Each of the next n − 1 lines contains two integers u and v (1 ≤ u, v ≤ n, u≠ v) meaning that there is an edge between vertices u and v in the tree.
  The data guarantees that the sum of n will not exceed 2 · 105

输出
For each test case print a single integer ——the minimum cost to ensure that every node is covered

#include<cstdio>
#include<cstring>
#include<algorithm>
#define M 1000005
#define INF 100000000000000
using namespace std;
struct E{
	int to,nx;
}edge[M<<1];
int tot,head[M];
void Addedge(int a,int b){
	edge[++tot].to=b;
	edge[tot].nx=head[a];
	head[a]=tot;
}
long long dp[M][3];
int fa[M];
int A[M];
inline void Add(long long &x,long long y){
	x+=y;
	if(x>=INF)x=INF;
}
void dfs(int now){
	dp[now][0]=dp[now][1]=dp[now][2]=0;
	dp[now][1]=A[now];dp[now][2]=INF;
	for(int i=head[now];i;i=edge[i].nx){
		int nxt=edge[i].to;
		if(nxt==fa[now])continue;
		fa[nxt]=now;
		dfs(nxt);
		dp[now][2]=min(dp[now][2]+min(dp[nxt][1],dp[nxt][2]),dp[now][0]+dp[nxt][1]);
		Add(dp[now][1],min(dp[nxt][0],min(dp[nxt][1],dp[nxt][2])));
		Add(dp[now][0],dp[nxt][2]);
	}
}
int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		int n;
		scanf("%d",&n);
		memset(head,0,sizeof(head));
		tot=0;for(int i=1;i<=n;i++)head[i]=0;
		for(int i=1;i<=n;i++)scanf("%d",&A[i]);
		for(int i=1;i<n;i++){
			int a,b;
			scanf("%d%d",&a,&b);
			Addedge(a,b);
			Addedge(b,a);
		}
		dfs(1);
		long long ans=min(dp[1][1],dp[1][2]);
		printf("%lld\n",ans);
	}
	return 0;
}

1379 Mr. Liang play Card Game

题目描述:
  Recently, Mr. Liang has become obsessed with a card game and cannot break free from it. The game goes like this: there are n cards arranged in a row from left to right. Each card has a type and a level (initially, all card levels are 1). You can perform the following operations an unlimited number of times:
  Operation 1: Select a card and play it. Each card type has a value Vi . Playing a level 1 card yields a profit of Vi , playing a level 2 card yields a profit of P · Vi , playing a level 3 card yields a profit of P · P · Vi and so on. However, there is a restriction on the card level, with the maximum level being R.
  Operation 2: Select two adjacent cards of the same type and level, and merge them into a higher-level card.
  As his good friend, cv4456 would like to ask you what is the maximum profit Mr. Liang can obtain in the end?

输入:
  The input consists of multiple test cases. The first line contains a single integer t(1 ≤ t ≤ 50) — the number of test cases. Description of the test cases follows.
  The first line of each case are four integers,n,m,R,P(1 ≤ n ≤ 100, 1 ≤ m ≤ 20, 1 ≤ R ≤ 20, 1 ≤ P ≤ 10). denoting the number of cards, types of cards, the upper limit of card levels, and the doubling coefficient for higher-level cards.
T   he second line of each case are n integers ai (1 ≤ ai ≤ m),denoting the types of the n cards initially placed on the table.(all cards on the table is level 1)
  The third line of each case are m integers Vi (1 ≤ Vi ≤ 105 ),denoting the weight of each kinds of card. The data guarantees that there will be no more than 10 groups with a value of n exceeding 20.

输出
For each test case print a single integer —the maximum profit Mr. Liang can obtain in the end.

#include<cstdio>
#include<cstring>
#include<algorithm>
#define M 105
#define N 505
#define INF 100000000000000
using namespace std;
long long dp[M][M][N];
int val[M],A[M];
int n,max_level,K,P;
long long Base[N];
long long Get_val(int x){
	int level=(x-1)/K,Kind=(x-1)%K+1;
	return 1ll*Base[level]*val[Kind];
}
long long Solve(int L,int R,int p){
	if(L>R){
		if(p==0)return 0;
		return -INF;
	}
	if(L==R){
		if(p==0)return val[A[L]];
		if(p==A[L])return 0;
		return -INF;
	}
	if(dp[L][R][p]!=-1)return dp[L][R][p];
	long long res=-INF;
	if(p==0){
		for(int mid=L;mid<R;mid++){
			if(Solve(L,mid,0)!=-INF&&Solve(mid+1,R,0)!=-INF)res=max(res,Solve(L,mid,0)+Solve(mid+1,R,0));
		}
		for(int i=1;i<=max_level*K;i++){
			long long tmp=Solve(L,R,i);
			if(tmp==-INF)continue;
			res=max(res,tmp+Get_val(i));
		}
	}else if(p<=K){
		for(int i=L;i<=R;i++){
			if(A[i]==p){
				if(Solve(L,i-1,0)!=-INF&&Solve(i+1,R,0)!=-INF)res=max(res,Solve(L,i-1,0)+Solve(i+1,R,0));
			}
		}
	}else{
		for(int i=L;i<R;i++){
			if(Solve(L,i,p-K)!=-INF&&Solve(i+1,R,p-K)!=-INF){
				res=max(res,Solve(L,i,p-K)+Solve(i+1,R,p-K));
			}
		}
	}
	dp[L][R][p]=res;
	return res;
}
int main(){
	int T;
	scanf("%d",&T);
	Base[0]=1;
	while(T--){
		memset(dp,-1,sizeof(dp));
		scanf("%d%d%d%d",&n,&K,&max_level,&P);
		for(int i=1;i<=max_level;i++)Base[i]=1ll*Base[i-1]*P;
		for(int i=1;i<=n;i++)scanf("%d",&A[i]);
		for(int i=1;i<=K;i++)scanf("%d",&val[i]);
		printf("%lld\n",Solve(1,n,0));
	}
	return 0;
}

1380 Amazing spacecraft

题目描述:
 On this day, Sonetto purchased her first spacecraft (which can be considered as a convex polygon) and eagerly began to operate it. This spacecraft had a touch screen interface where the user could click on a position, and the spacecraft would instantly teleport to that location. However, since Sonetto bought a smuggled spacecraft, after Sonetto clicks on a location, the system randomly selects a point within a circle centered at Sonetto’s clicked position with a radius of R, and the spacecraft teleport to that point.On this day, there was a Mr.Cookie’s spacecraft parked in the vicinity, which can also be seen as a convex polygon. Now, given the position where Sonetto clicked on the screen, you are asked to calculate the probability of Sonetto0 s spacecraft colliding with Mr.Cookie’s spacecraft parked in the area.
 Because the space where Sonetto is located is a rather mysterious space, Sonetto’s spacecraft may initially intersect with Mr.Cookie0 s spacecraft. However, we don’t need to be concerned about Sonetto0 s initial position. We only need to focus on whether the position of her spacecraft after the instant teleportation will collide with Mr.Cookie’s spacecraft.
 To be more specific, you are given two convex polygons A and B, and a circle P (centered at point X with radius R). You need to determine the probability of randomly selecting a point S within the circle P, such that when the convex polygon A moves along the vector 在这里插入图片描述 (O is the origin point (0,0)), it transforms into a new convex polygon A’ , and A’ intersects with B (intersection implies that there exists a point w such that w ∈ A’ and w ∈ B)

输入:
 The input consists of multiple test cases.  The first line contains a single integer t(1 ≤ t ≤ 1200) — the number of test cases. Description of the test cases follows.
 The second line contains a integer n (3 ≤ n ≤ 30000), denoting the number of vertices of the convex polygons A.
 Then follows n lines, each line contains two integers xi , yi (−108 ≤ xi , yi ≤ 108 ), denoting the ith point of the convex polygon A. The points are given in counter-clockwise order. The next line contains a integer m (3 ≤ m ≤ 30000), denoting the number of vertices of the convex polygons B.
 Then follows m lines, each line contains two integers xi , yi (−108 ≤ xi , yi ≤ 108 ), denoting the ith point of the convex polygon B. The points are given in counter-clockwise order.
 The last line contains three integers x,y and r,denoting the position of the center of the circle P and the radius of the circle. (−108 ≤ xi , yi ≤ 108 , 1 ≤ r ≤ 108 )
 The data guarantees that the sum of n will not exceed 2 · 105
 The data guarantees that the sum of m will not exceed 2 · 105

输出
For each test case print a single floating-point number denoting the probability of A’ intersects with B.(keep 4 decimal places)

#include<cstdio>
#include<cstring>
#include<stack>
#include<algorithm>
#include<cmath>
#include<cassert>
#include<ctime>
#include<queue>
#define eps 1e-8
using namespace std;
using int64=long long;
using uint64 = unsigned long long;
const double pi = acos(-1);
const double PI = acos(-1);
inline int sign(int64 k) {
	if(k > 0) {
		return 1;
	} else if(k < 0) {
		return -1;
	}
	return 0;
}
inline int sign(double k) {
	if(k > eps) {
		return 1;
	} else if(k < -eps) {
		return -1;
	}
	return 0;
}
double pow2(double x){return x*x;}

inline int comp(int64 k1 , int64 k2) {
	return sign(k1 - k2);
}
inline int comp(double k1 , double k2) {
	return sign(k1 - k2);
}

inline double sqr(double x){
	return x*x;
}

struct dbPoint {
	double x , y;

	dbPoint(double _x = 0 , double _y = 0) : x(_x) , y(_y) {}
	dbPoint operator + (const dbPoint &rhx) const {
		return (dbPoint){x + rhx.x , y + rhx.y};
	}
	dbPoint operator - (const dbPoint &rhx) const {
		return (dbPoint){x - rhx.x , y - rhx.y};
	}
	dbPoint operator * (const double &k) const {
		return (dbPoint){x * k , y * k};
	}
	dbPoint operator / (const double &k) const {
		return dbPoint(1.0*x / k , 1.0*y / k);
	}

	int operator ==(const dbPoint &rhx) const {
		return comp(x , rhx.x) == 0 && comp(y , rhx.y) == 0;
	}
	int operator !=(const dbPoint &rhx) const {
		return !((*this)==rhx);
	}
/*	Point turn(double k) {
		return (Point){x * cos(k) - y * sin(k) , x * sin(k) + y * cos(k)};
	}*/
	dbPoint turn90() {
		return (dbPoint){-y , x};
	}
	int operator <(const dbPoint &rhx) const {
		int d = comp(x , rhx.x);
		switch(d) {
			case -1:
				return 1;
			case 1:
				return 0;
			default:
				return comp(y , rhx.y) == -1;
		}
	}
	double abs() {
		return sqrt(x * x + y * y);
	}
	double abs2() {
		return x * x + y * y;
	}
	double dis(const dbPoint &rhx) const {
		return (*(this) - rhx).abs();
	}
	dbPoint getdel() { // ?
		if(sign(x) == -1 || (sign(x) == 0 && sign(y) == -1)) {
			return (*this) * (-1);
		} else {
			return (*this);
		}
	}
	int getP() const {
		return sign(y) == 1 || (sign(y) == 0 && sign(x) == 1);
	}
	void Print(){
		printf("%lf %lf\n",x,y);
	}
};
struct  Point  {
	int64 x , y;

	Point(int64 _x = 0 , int64 _y = 0) : x(_x) , y(_y) {}
	Point operator + (const Point &rhx) const {
		return (Point){x + rhx.x , y + rhx.y};
	}
	Point operator - (const Point &rhx) const {
		return (Point){x - rhx.x , y - rhx.y};
	}
	Point operator * (const int64 &k) const {
		return (Point){x * k , y * k};
	}
	/*dbPoint operator * (const double &k) const {
		return (dbPoint){1.0*x * k , 1.0*y * k};
	}*/
	
	int64 cross(Point _)const{
		return x*_.y-y*_.x;
	}
	int64 cross(Point a,Point b)const{
		return (a-*this).cross(b-*this);
	}
	int operator ==(const Point &rhx) const {
		return comp(x , rhx.x) == 0 && comp(y , rhx.y) == 0;
	}
	int operator !=(const Point &rhx) const {
		return !((*this)==rhx);
	}
/*	Point turn(double k) {
		return (Point){x * cos(k) - y * sin(k) , x * sin(k) + y * cos(k)};
	}*/
	Point turn90() {
		return (Point){-y , x};
	}
	int operator <(const Point &rhx) const {
		int d = comp(x , rhx.x);
		switch(d) {
			case -1:
				return 1;
			case 1:
				return 0;
			default:
				return comp(y , rhx.y) == -1;
		}
	}
	double abs() {
		return sqrt(x * x + y * y);
	}
	int64 abs2() {
		return x * x + y * y;
	}
	double dis(const Point &rhx) const {
		return (*(this) - rhx).abs();
	}
	Point getdel() { // ?
		if(sign(x) == -1 || (sign(x) == 0 && sign(y) == -1)) {
			return (*this) * (-1);
		} else {
			return (*this);
		}
	}
	int getP() const {
		return sign(y) == 1 || (sign(y) == 0 && sign(x) == 1);
	}
	void Print(){
		printf("%lld %lld\n",x,y);
	}
	dbPoint Change(){
		return (dbPoint){1.0*x,1.0*y};
	}
};

// L -> Line , S -> Segment
int inside(Point k1 , Point k2 , Point k3) { // k3 in [k1 , k2]
	return inside(k1.x , k2.x , k3.x) && inside(k1.y , k2.y , k3.y);
}
int64 dot(Point k1 , Point k2) {
	return k1.x * k2.x + k1.y * k2.y;
}
int64 cross(Point k1 , Point k2) {
	return k1.x * k2.y - k1.y * k2.x;
}
double cross(pair<double,double> k1 , pair<double,double> k2) {
	return k1.first * k2.second - k1.second * k2.first;
}
double cross(dbPoint k1 , dbPoint k2) {
	return k1.x * k2.y - k1.y * k2.x;
}

bool cmp(Point K1,Point K2){//jijiao sort
    if(K1.getP()!=K2.getP()){
        return K1.getP()==1;
    }else{
        return cross(K1,K2)>0;
    }
}

double get_angle(Point x,Point y){
	return acosl((x.abs2()+y.abs2()-x.dis(y)*x.dis(y))/(2.0l*x.abs()*y.abs()));
}
int checkLS(Point k1,Point k2,Point k3,Point k4){
	Point v=k2-k1;
	Point l=k3-k1,r=k4-k1;
	//if(cross(l,r)<0)swap(l,r);
	//printf("%lf %lf %lf\n",get_angle(v,Point(1,0)),get_angle(l,Point(1,0)),get_angle(r,Point(1,0)));
	//v.Print();l.Print();r.Print();
	//printf("@%lld @%lld\n",cross(l,v),cross(v,r));
	return sign(cross(l,v))*sign(cross(v,r))>=0;
}
Point Base;
bool cmp_cc(const Point x,const Point y){
	return Base.cross(x,y)>0;
}
bool Contain_convex(const vector<Point>&A,Point p){
	assert((int)A.size()>=3);
	Base=A[0];
	if(Base.cross(p,A[1])>0||Base.cross(p,A.back())<0)return false;
	//if(Base.cross(p,A[1])==0)puts("@");
	if(Base.cross(p,A[1])==0){
		if((p-Base).abs2()<=(A[1]-Base).abs2())return true;
		return false;
	}
	//if(Base.cross(p,A[1])==0&&(p-Base).abs2()>(A[1]-Base).abs2())return true;
	int i=lower_bound(A.begin(),A.end(),p,cmp_cc)-A.begin()-1;
	int j=i+1;
	assert(i>=0);
	assert(j<(int)A.size());
	return (A[i].cross(A[j],p))>=0ll;
}
int clockwise(Point k1 , Point k2) { //
	return sign(cross(k1,k2));
}
vector<Point> ConvexHull(vector<Point>A,int flag=1){//flag =0 not yange flag=1 yange
	int n=A.size();vector<Point>ans(n*2);
	sort(A.begin(),A.end());int now=-1;
	for(int i=0;i<n;i++){
		while(now>0&&sign(cross(ans[now]-ans[now-1],A[i]-ans[now-1]))<flag)now--;
		ans[++now]=A[i];
	}int pre=now;
	for(int i=n-2;i>=0;i--){
		while(now>pre&&sign(cross(ans[now]-ans[now-1],A[i]-ans[now-1]))<flag)now--;
		ans[++now]=A[i];
	}ans.resize(now);return ans;
}
vector<Point> Minkowski(vector<Point>A,vector<Point>B){
    vector<Point>C(A.size()+B.size()+1),v1(A.size()),v2(B.size());
	for(int i=0;i<(int)A.size();i++)v1[i]=A[(i+1)%A.size()]-A[i];
    for(int i=0;i<(int)B.size();i++)v2[i]=B[(i+1)%B.size()]-B[i];
    int cnt=0;
    C[cnt]=(A[0]+B[0]);
    int p1=0,p2=0;
    while(p1<(int)A.size()&&p2<(int)B.size()){
        ++cnt;
        if(sign(cross(v1[p1],v2[p2]))>=0)
            C[cnt]=C[cnt-1]+v1[p1++];
        else 
            C[cnt]=C[cnt-1]+v2[p2++];
    }
    while(p1<(int)A.size()){
        ++cnt;
        C[cnt]=C[cnt-1]+v1[p1++];
    }
    while(p2<(int)B.size()){
        ++cnt;
        C[cnt]=C[cnt-1]+v2[p2++];
    }
    return C;
}
struct Circle {
	Point o ; double r;
	int inside(Point k) {
		return comp(r , o.dis(k));
	}
	double area(){
		return PI*r*r;
	}
};
double TriAngleCircleInsection(Circle C, Point A, Point B)
{
    Point OA=A-C.o,OB=B-C.o;
    Point BA=A-B, BC=C.o-B;
    Point AB=B-A, AC=C.o-A;
    double DOA=OA.abs(),DOB=OB.abs(),DAB=AB.abs(),r=C.r;
    if(sign(cross(OA,OB))==0) return 0;
    if(sign(DOA-C.r)<0&&sign(DOB-C.r)<0) return cross(OA,OB)*0.5; 
    else if(DOB<r&&DOA>=r)
    {
        double x=(dot(BA,BC)+sqrt(r*r*DAB*DAB-cross(BA,BC)*cross(BA,BC)))/DAB;
        double TS=cross(OA,OB)*0.5;
        return asin(TS*(1-x/DAB)*2/r/DOA)*r*r*0.5+TS*x/DAB;
    }
    else if(DOB>=r&&DOA<r)
    {
        double y=(dot(AB,AC)+sqrt(r*r*DAB*DAB-cross(AB,AC)*cross(AB,AC)))/DAB;
        double TS=cross(OA,OB)*0.5;
        return asin(TS*(1-y/DAB)*2/r/DOB)*r*r*0.5+TS*y/DAB;
    }
    else if(fabs(cross(OA,OB))>=r*DAB||dot(AB,AC)<=0||dot(BA,BC)<=0)
    {
        if(dot(OA,OB)<0){
            if(cross(OA,OB)<0) return (-acos(-1.0)-asin(cross(OA,OB)/DOA/DOB))*r*r*0.5;
            else  return ( acos(-1.0)-asin(cross(OA,OB)/DOA/DOB))*r*r*0.5;
        }
        else      {
			return asin(cross(OA,OB)/DOA/DOB)*r*r*0.5;
		}
    }
    else
    {
        double x=(dot(BA,BC)+sqrt(r*r*DAB*DAB-cross(BA,BC)*cross(BA,BC)))/DAB;
        double y=(dot(AB,AC)+sqrt(r*r*DAB*DAB-cross(AB,AC)*cross(AB,AC)))/DAB;
        double TS=cross(OA,OB)*0.5;
        return (asin(TS*(1-x/DAB)*2/r/DOA)+asin(TS*(1-y/DAB)*2/r/DOB))*r*r*0.5 + TS*((x+y)/DAB-1);
    }
}
double Get_Area(vector<Point>A,Circle X){
	double res=0.0;
	int n=(int)A.size();
	A.push_back(A[0]);
	for(int i=0;i<n;i++){
		res+=TriAngleCircleInsection(X,A[i],A[i+1]);
	}
	return fabs(res);
}
double Get_ans(vector<Point>A,vector<Point>B,Circle X){
	int n=(int)A.size();
	for(int i=0;i<n;i++){
        A[i].x=-A[i].x;
        A[i].y=-A[i].y;
    }
    A=ConvexHull(A,1);
    B=ConvexHull(B,1);
    vector<Point>C=Minkowski(A,B);
    C=ConvexHull(C,1);
    return 1.0*Get_Area(C,X)/X.area();
}
int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		int n,m;
	    scanf("%d",&n);
	    vector<Point>A(n);
	    for(int i=0;i<n;i++)scanf("%lld%lld",&A[i].x,&A[i].y);
	    scanf("%d",&m);
	    vector<Point>B(m);
	    for(int i=0;i<m;i++)scanf("%lld%lld",&B[i].x,&B[i].y);
	    Circle X;
	    scanf("%lld%lld%lf",&X.o.x,&X.o.y,&X.r);
	    printf("%.4lf\n",Get_ans(A,B,X));
	}
	return 0;
}

1381 Cyclically Isomorphic

题目描述:
 If there exists an integer k such that string S becomes equal to string T after being cyclically rightshifted by k positions, then the strings S and T are said to be cyclically right-shifted.
 Now, given n strings of length m consisting of lowercase letters , there are a total of Q queries. Each query provides two positive integers x and y. If the strings sx and sy are cyclically right-shifted, output ’Yes’; otherwise, output ’No’.

输入:
 The input consists of multiple test cases.  The first line contains a single integer T(1 ≤ T ≤ 5) — the number of test cases. Description of the test cases follows.
 The first line of each test case contains two integers n and m (1 ≤ n × m ≤ 105 )— the number of the strings and the length of strings.
 Each of the next n lines contains a string of lowercase letters si .
 The next line contains a positive integer Q (1 ≤ Q ≤ 105 ).
 Each of the next Q lines contains two integers x, y (1 ≤ x, y ≤ n) asks whether the string sx and the string sy are cyclic isomorphic.

输出
For each test case, output Q lines. Each line should contain a string indicating whether the current query strings sx and sy are cyclically isomorphic. If they are cyclically isomorphic, output ’Yes’; otherwise, output ’No’

#include<bits/stdc++.h>
using namespace std;
const int Mod = 666623333;
int T, n, m, Q, a[100005];
char s[200005];
int main(){
	scanf("%d", &T);
	while (T--){
		scanf("%d%d", &n, &m);
		for (int i = 1; i <= n; i++){
			scanf("%s", s + 1);
			for (int j = m + 1; j <= m + m; j++)
				s[j] = s[j - m];
			int I = 1, J = 2;
			while (J <= m){
				ok:;
				for (int k = 0; k < m; k++){
					if (s[I + k] < s[J + k]){
						J += k;
						break;
					}
					if (s[I + k] > s[J + k]){
						int tmp = I;
						I = J;
						J = max(J, tmp + k);
						break;	
					}
				}
				J++;
			}
			a[i] = 0;
			for (int j = 0; j < m; j++)
				a[i] = (31ll * a[i] + s[I + j] - 'a' + 1) % Mod;
		}
		scanf("%d", &Q);
		while (Q--){
			int x, y;
			scanf("%d%d", &x, &y);
			if (a[x] == a[y])
				puts("Yes");
			else
				puts("No");
		}
	}
	return 0;
}

1382 固执的RT

题目描述:
 RT你的帮助下取走了足够多的树枝,并用木制的马车拉着树枝去与人马决一死战。但他忘了一件事,人马是会喷火的。在战斗进行到一半时,卑鄙的人马用火焰将RT所有树枝烧光了。一般人可能已经放弃了,但固执的RT不愿意放弃。他决定再去收集树枝,和人马进行第二次战斗。
 RT现在收集了n个树枝,第i个树枝的攻击力为ai。RT如果想打败人马,收集到的树枝攻击力之和至少为m。请你帮RT判断他现在收集到的树枝是否足够打败人马。
 如果可以请输出“YES”, 否则输出“NO”(输出不带引号)。

输入:
 第一行两个整数n,m。分别是树枝的数量和RT需要收集的树枝攻击力之和的最低要求。(1≤ n≤1e5, 1≤m≤1e9)
 第二行n个正整数,代表n个树枝的攻击力。(1≤ai≤1e9)

输出
一行,如果RT收集到的树枝可以击败人马,输出“YES”,否则输出“NO”

#include <iostream>

using namespace std;

int main()
{
    int n, m;
    long long sum = 0;
    cin >> n >> m;
    while (n -- )
    {
        int x;
        cin >> x;
        sum += x;
    }
    puts(sum >= m ? "YES" : "NO");
    return 0;
}

1383 奶牛的寿命

题目描述:
 上帝养了一头奶牛,但是有一天奶牛偷吃了上帝草药,上帝十分生气于是奶牛必须要去地狱接受惩罚,上帝给了奶牛一个长达n的刑期但是同样允许奶牛对刑期进行最多操作log2(n)+1次,每次操作可以交换刑期的二进制形式下任意的两个位置上的数字,但是不能改变原来的二进制数的位数(不能有前导零),奶牛自然希望可以尽可能多的减刑,请问出奶牛最多可以减少多少刑期?

输入:
一个正整数n表示奶牛当前刑期。(n<2^31)

输出
一个整数表示奶牛最多可以减少的刑期

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n;
    cin >> n;
    bitset<31> m(n);
    int num = m.count() - 1;//num为二进制一的个数-1
    bool flag = 0;//判断有没有出现第一个1
    for (int i = 30; i >= 0;i--)
    {
        if(i<num)m[i] = 1;
        else if(flag)m[i] = 0;
        if(m[i]&1) flag = 1;
    }
    cout <<n-m.to_ulong();
    return 0;
}

1384 爬山

题目描述:
 暑假学校组织同学去景区爬山,但是当地的山峰分布十分奇特,所有的山峰都分布在一条东西走向的直线上(入口在东,出口在西),为了提高同学们的身体素质学校给同学们规定了一个“运动指标”,“运动指标“等于攀爬过程中上山高度与下山的高度的和。幸运的是景区给游客提供了缆车服务(缆车的行驶路线平行于地面),游客可以在景区入口选择任意一个高度乘坐缆车但是从此以后乘坐缆车的高度不能再发生改变,由于缆车不能穿过山体,所以当缆车的行驶高度低于当前山峰高度时缆车内游客需要在当前高度的东面山体下车并步行翻过山峰,当到达西面山体的缆车高度时游客需要继续乘坐缆车直到到达景区出口。例如景区三座山峰高度分别为100米、200米、150米,当选择缆车高度为120时,第一座山峰无需攀爬,第二座山峰需要攀爬80米,第三座山峰需要攀爬30米。
 位置越高缆车上的风景越好,小明希望能看到最好风景但是同时需要满足学校要求的“运动指标”。

输入:

 第一行两个正整数N、P,N表示景区山峰数量,P表示“运动指标”。
 第二行N个正整数,表示每座山峰的高度。
(1<=N<=1e5,1<=P<=1e9,1<=山峰高度<=1e9)

输出
一个非负整数表示你选择的缆车高度H,如果怎样安排都无法满足则输出-1。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
typedef long long LL;
int n, p,a[N];
bool func(int h)
{
    LL sum = 0;
    for (int i = 1; i <= n;i++)
        if(a[i]>h)sum += a[i] - h;
    return sum*2>=p;//包括上山高度+下山高度,即攀爬高度*2
}
int main()
{
    LL sum = 0;
    cin >> n >> p;
    for (int i = 1; i <= n;i++)
        cin >> a[i],sum+=a[i];
    if(sum*2<p)//即使缆车高度为0也不可能完成运动指标
    {
        cout << -1;
        return 0;
    }
    int l = 0, r = 0x3f3f3f3f;
    while(l<=r)
    {
        int mid = l + r >> 1;
        if(func(mid))l = mid + 1;
        else r = mid - 1;
    }
    cout <<l-1;
    return 0;
}

1385 释怀的RT

题目描述:
 又一次收集完树枝后,RT做了防火工作,这次RT成功的使用了树枝战胜了人马。经过了长时间的痛苦折磨,RT释怀了并决定去海拉卢达陆上狩猎岩石巨人,用岩石巨人的心岩照亮心形湖来祭奠他还未开始就结束的爱情。
 假设心形湖由1n个方格构成,RT在每个方格上放了一个心岩,每个心岩有一个照亮范围x,代表着这块心岩可以照亮它左边x个方格和右边x个方格,但不能照亮心岩所在的方格(假如一个心岩在第5个方格,x=2,那么他只能照亮第3,4和第6,7个方格),现在请你求出心形湖有多少个方格被照亮。

输入:
第一行一个正整数n,心形湖格子的个数。( 1 ≤ n ≤ 1e6)
第二行n个整数,第i个数表示第i个心岩能照亮的范围。(0≤ x i x_i xi≤ 1e9)

输出
一行,一个整数,表示照亮的格子数

#include <iostream>

using namespace std;

const int N = 1e6 + 10;

int n, x, pre[N];
void solve() {
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> x;
        pre[max(1, i - x)]++, pre[i]--;
        pre[i + 1]++, pre[min(n + 1, i + x + 1)]--;
    }
    int cnt = 0, now = 0;
    for (int i = 1; i <= n; i++) {
        now += pre[i];
        cnt += now > 0;
    }
    cout << cnt << endl;
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    solve();
    return 0;
}

1386 自动收小麦机

题目描述:
 在游戏MC(我的世界)中,如果小麦碰到水流就会掉落,但是mc中的水不能无限流动,在同一高度一桶水往一个方向流最多可以流动8格(算上本身一格)
在这里插入图片描述

 但是如果流动过程中遇到了阶梯下降了高度,则从下降的那一格开始重新计算距离,所以根据这个原理可以设计一种自动收小麦机,只需要从最高处倒一桶水就可以把所有小麦变成掉落物

在这里插入图片描述

 这次小小航也根据这个原理建造了一个自动收小麦机,但是小小航并没有精确的计算台阶的位置,当小小航建造完后发现机器不能一次收集所有小麦,现在已知小小航的收小麦机总长为 n 格 ,水流可以流 k 格,每一格上的小麦数量为ai。 共有q次询问(每次询问之间互不影响),每次询问一个整数x,在第x格放一桶水共可以收获多少小麦。(水只会从高的一端流向低的一端)

输入:
第一行三个整数n,q,k
第二行 n个数表示每格上小麦的数量
第三行n个数表示每格的高度,保证非递减
接下来q行 每行一个数x,表示在第x格放一桶水

输出
q行,每行一个整数,表示能收获的小麦数量。

#include <iostream>
#include <cstring>

using namespace std;

const int N = 1000010, M = 200010;
const int inf = 1e9;

using i64 = long long;

int a[N], h[N];
i64 s[N];
int l[N];
int stk[N], tt;

int main() {
  int n, q, k;
  cin >> n >> q >> k;
  for (int i = 1; i <= n; i++) {
    cin >> a[i];
    s[i] = s[i - 1] + a[i];
  }
  for (int i = 1; i <= n; i++) {
    cin >> h[i];
  }
  for (int i = 1; i <= n; i++) {
    while (tt && h[stk[tt]] == h[i]) tt--;
    if (tt) {
      if (stk[tt] >= i - k + 1) l[i] = l[stk[tt]];
      else l[i] = max(i - k, 0);
    } else {
      l[i] = max(i - k, 0);
    }
    stk[++tt] = i;
    
  }
  while (q--) {
    int x;
    cin >> x;
    cout << s[x] - s[l[x]] << '\n';
  }
  return 0;
}

1387 卡特兰数

题目描述:
 卡特兰数是组合数学中一个常出现于各种计数问题中的数列。以中国蒙古族数学家明安图和比利时的数学家欧仁·查理·卡特兰的名字来命名,其前几项为(从第0项开始):1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, 208012, 742900, 2674440, 9694845, 35357670, 129644790, 477638700, 1767263190, 6564120420, 24466267020, 91482563640, 343059613650, 1289904147324, 4861946401452, …
卡特兰数公式:h(n) =在这里插入图片描述

给定一个整数n,请你求出 在这里插入图片描述末尾有多少个连续的0。

输入:
一个整数n。(1 <= n <= 5e6)

输出
一个整数,代表前n项卡特兰数之积末尾连续0的数量

#include <iostream>

using namespace std;

const int N = 5e6 + 10;

int cnt2[N], cnt5[N];

int func(int x, int t)
{
    int res = 0;
    while (x % t == 0)
    {
        res ++ ;
        x /= t;
    }
    return res;
}

int main()
{
    int n;
    cin >> n;
    for (int i = 1; i <= n; i ++ )
    {
        cnt2[i] = cnt2[i - 1], cnt5[i] = cnt5[i - 1];
        
        cnt2[i] += func(4 * i - 2, 2);
        cnt5[i] += func(4 * i - 2, 5);
        
        cnt2[i] -= func(i + 1, 2);
        cnt5[i] -= func(i + 1, 5);
    }
    for (int i = 1; i <= n; i ++ )
    {
        cnt2[i] += cnt2[i - 1];
        cnt5[i] += cnt5[i - 1];
    }
    cout << min(cnt2[n], cnt5[n]);
}

1388 异星突击

题目描述:
  公元2348年,人类与外星帝国爆发了星际战争,但是人类的科技过于落后,在正面战场节节败退。现在ZH是人类派出的唯一一艘恒星级战舰的指挥官。ZH需要穿越星海突击敌军母星,但是外星帝国在路上布置了很多引力波屏障,这种屏障需要特制的攻城武器才能攻破。
  恒星级战舰十分强大,可以挂载无限多的攻城武器,但是初始时没有挂载武器,战舰的初始结构值为hp ,在突破的路上ZH会遇到一下几种事件:
   0 x 战舰获得了一门属性值为 x 的武器;
   1 x 战舰跃迁过程中损坏了一门属性值为 x 的武器,保证损坏的武器原来一定存在;
   2 x h 战舰遇到了一个屏障,屏障的结构值为 h,特征值为 x,每个武器对它造成的伤害为( ⊕的意思是按位异或),输出 战舰中可以对屏障造成伤害 大于 h 的武器数量,如果没有可以一次击破屏障的武器,战舰会直接强行穿过屏障,但是会减少一点结构值。
最后输出战舰剩余结构值
 保证战舰结构值最终大于等于0。

输入:
第一行输入为两个整数n,hp
接下来n 行每行为一个事件
0 ≤ \leq x,hp, h ≤ \leq 1 0 9 10^9 109

输出
每次事件2输出一个整数为可用武器数量占一行
最后输出战舰剩余结构值

#include <bits/stdc++.h>
using namespace std;
using i64 = int64_t;
struct Node {
  int sum;
  array<Node *, 2> ch;
  Node() : sum(0) { ch.fill(nullptr); }
};
int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  int n, hp;
  cin >> n >> hp;
  Node *root = new Node();
  for (int i = 0, op, x, h; i < n; i += 1) {
    cin >> op >> x;
    if (op == 0) {
      auto p = root;
      for (int i = 29; i >= 0; i -= 1) {
        int j = (x >> i) % 2;
        if (p->ch[j] == nullptr) {
          p->ch[j] = new Node();
        }
        p = p->ch[j];
        p->sum += 1;
      }
    } else if (op == 1) {
      auto p = root;
      for (int i = 29; i >= 0; i -= 1) {
        int j = (x >> i) % 2;
        p = p->ch[j];
        p->sum -= 1;
      }
    } else {
      cin >> h;
      int ans = 0;
      auto p = root;
      for (int i = 29; i >= 0; i -= 1) {
        int j = (x >> i) % 2;
        int k = (h >> i) % 2;
        if (k == 0) {
          if (p->ch[j ^ 1]) {
            ans += p->ch[j ^ 1]->sum;
          }
          if (p->ch[j]) {
            p = p->ch[j];
          } else {
            break;
          }
        } else {
          if (p->ch[j ^ 1]) {
            p = p->ch[j ^ 1];
          } else {
            break;
          }
        }
      }
      cout << ans << "\n";
      hp -= ans == 0;
    }
  }
  cout << hp << "\n";
}

1389 悲伤的RT

题目描述:
  RT在表白后被拒,悲伤的RT决定去塞尔达·王国之泪里折磨人马发泄。为此,RT用马车拉了n个树枝(第i个树枝的攻击力为ai ,1 ≤ \leq i ≤ \leq n,1 ≤ \leq a i a_i ai ≤ \leq 1e9),准备用树枝与人马决斗。
 善良的海利亚女神不想看到RT这样折磨人马和他自己,就用魔法给RT加了一个限制:他只能拿马车中前 ⌊ n c ⌋ \lfloor \frac{n}{c} \rfloor cn个攻击力最小的树枝去和人马战斗(当c = 2, 树枝的攻击力为{1,2,3,4,5}时,RT可以拿走攻击力为1和2的树枝)。
 但邪恶的加农多夫给了RT一个邪恶的魔法。RT可以把这n个树枝分成若干个连续的部分(假如a = {1,2,3,4},{{1,2},{3,4}}是一种合法的分割方式,但{{1,3},{2,4}}不是),装在不同的马车上,然后对这些马车施加魔法,这样RT可以从每个马车上取走该马车上前 ⌊ k c ⌋ \lfloor \frac{k}{c} \rfloor ck个攻击力最小的树枝(k为马车上树枝的数量)。
 现在请你帮RT算出他所能取出的树枝攻击力之和最大是多少?

输入:
第一行两个正整数n和c。树枝的总数量和海利亚女神对RT的限制。(1 ≤ \leq n,c ≤ \leq 1e6) 第二行n个正整数,n个树枝的攻击力 。( 1 ≤ \leq ai ≤ \leq 1e9)

输出
一个整数,RT所能取出的树枝攻击力之和最大值

#include <bits/stdc++.h>
using namespace std;
using i64 = int64_t;
struct Node {
  int sum;
  array<Node *, 2> ch;
  Node() : sum(0) { ch.fill(nullptr); }
};
int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  int n, c;
  cin >> n >> c;
  vector<int> a(n + 1);
  for (int i = 1; i <= n; i += 1) {
    cin >> a[i];
  }
  vector<i64> dp(n + 1);
  set<pair<int, int>> sp;
  for (int i = 1; i <= n; i += 1) {
    dp[i] = dp[i - 1];
    sp.emplace(a[i], i);
    if (i > c) {
      sp.erase({a[i - c], i - c});
    }
    if (i >= c) {
      dp[i] = max(dp[i - c] + sp.begin()->first, dp[i]);
    }
  }
  cout << dp[n];
}

1390 欢乐颂

题目描述:
 《欢乐颂》是一篇科幻小说,由中国著名科幻作家刘慈欣发表于2005年8月份的《九州幻想》上,是刘慈欣“大艺术系列”的小说之一(同为“大艺术系列”的小说之还有《诗云》、《梦之海》),全文约三万字。
  在文章中一位宇宙音乐家来到了地球,他在地球举办了一场美妙且震撼的音乐会。音乐家有一面神奇琴,琴面上有n个琴柱(琴柱从1……n进行编号),每个琴柱都可以发射一种能量这里命名为“弦值”,只有拥有相同“弦值”的不同琴柱之间才可以连接一条琴弦,每个琴柱可以发射多个“弦值”当然也可以不发射。琴弦的产生需要大量的能量,假设两个琴柱各自发射的”弦值“之和分别为a、b,则产生琴弦的能量为(a^b)+1【(a异或)b+1】。
  现在音乐家需要演奏一段音乐并且他只有n-1次连接琴柱的机会,音乐演奏完成的条件是:所有的琴柱必须都直接或间接相连并且音乐家希望使用的能量尽可能的少。 音乐家为了保证只有一种琴柱连接方式,所以在满足音乐演奏完成的情况下他会优先选择连接消耗能量较少的琴弦,如果消耗能量相同则选择x*n+y较小的(x是琴弦上编号较小的琴柱,y是琴弦上编号较大的琴柱,n为琴柱数量)。音乐家希望回收所有琴弦的能量,但是如果有琴柱连接不完整那么所有的琴弦都会奔溃,因此音乐家最多只有一次回收的机会,回收能量的方式为:选择两个琴柱(可能直接或间接相连),连接这两个琴柱的琴弦所拥有的的能量都会被回收。
  音乐家想知道最后他最多可以回收多少能量。

输入:
第一行一个正整数n表示琴柱的数量。
接下来n行,第i行给出一个非负数k表示第i-1号琴弦发射的”弦值“数量,后面有k个正整数a[i](1<=i<=k)表示i-1号琴柱发射的每个”弦值“的大小。
(输入保证最后可以选择连接的琴柱对数m不超过1000000,每种弦值出现次数不超过1000) (n<=1e5,k<=10,a[i]<=1e6)

输出
一个数字表示最多可以回收的能量。

#include<bits/stdc++.h>
#define LL long long
#define PII pair<int,int>
#define x first
#define y second
using namespace std;
const int N=1e5+10,M=1e6+10;
typedef struct edges{int x,y,w;}edges;
vector<int> v1,v2[M];//v1记录所有弦值的种类,v2记录每种弦值所具有的琴柱编号
vector<PII> v[N];//储存最小生成树
edges edge[M];//储存所有可以连接的的边
bool st[M];//标记弦值避免重复添加
int num[N],a[N];//num统计每个琴柱所拥有的弦值的和,a是并查集数组
int n,ans;
LL res,dp[N];//dp记录当前节点的到叶子节点最长距离
bool cmp(edges xx,edges yy)//排序
{
    if(xx.w!=yy.w)return xx.w<yy.w;
    else if(xx.x!=yy.x)return xx.x<yy.x;
    return xx.y<yy.y;
}
int find1(int x)//并查集
{
    if(x!=a[x])a[x]=find1(a[x]);
    return a[x];
}
void DP(int u,int p)//树形dp查找树的直径,u是当前节点,p是u的父节点
{
    for(auto it:v[u])
    {
        if(it.x==p)continue;
        DP(it.x,u);
        res=max(res,dp[it.x]+dp[u]+it.y);
        dp[u]=max(dp[u],dp[it.x]+it.y);
    }
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        int k,x;
        cin>>k;
        while(k--)
        {
            cin>>x;
            num[i]+=x;
            v2[x].push_back(i);
            if(!st[x])v1.push_back(x),st[x]=1;
        }
        a[i]=i;
    }
    for(int it:v1)//建图
    {
        sort(v2[it].begin(),v2[it].end());//保证edge中小编号琴柱为edge.x
        for(int i=0;i<v2[it].size();i++)
            for(int j=i+1;j<v2[it].size();j++)
            edge[ans++]={v2[it][i],v2[it][j],(num[v2[it][i]]^num[v2[it][j]])+1};
    }
    sort(edge,edge+ans,cmp);//根据题目信息排序
    int sum=0;
    for(int i=0;i<ans&&sum!=n-1;i++)//Kruskal求最小生成树
    {
        int x=edge[i].x,y=edge[i].y,w=edge[i].w;
        int x1=find1(x),y1=find1(y);
        if(x1==y1)continue;
        a[x1]=y1;
        v[x].push_back({y,w});//建树
        v[y].push_back({x,w});
        sum++;
    }
    if(sum!=n-1)cout<<0<<endl;//无法建立最小生成树
    else
    {
        DP(1,0);//以1为根开始
        cout<<res<<endl;
    }
    return 0;
}

1391 最长连续相同字符

题目描述:
 给你一个仅有小写字母组成且长度为n的字符串a以及m条指令。
指令有以下两种类型:
  1 l r ,查询区间[l,r]中最长连续相同字符串并输出该字符串的左右边界,如果有多个,输出左边界最小的那个
  2 x ch,将a[x]改为ch,字符串下标从1开始

输入:
第一行两个正整数n和m。(1 ≤ \leq n,m ≤ \leq 1e5)
第二行一个长度为n的字符串a,a仅有小写字母构成
接下来m行,每行一条指令,每行首先有一个整数op,表示操作的类型。
1.若op = 1,则接下来有两个整数l,r,表示查询区间[l,r]内最长连续相同字符串。
2.若op = 2,则接下来有一个正整数x和一个字符ch,表示将字符串中下标为x的字符修改为ch

输出
对于每个查询指令,输出两个整数,代表区间的左右边界
每个答案占一行

#include <iostream>

using namespace std;

const int N = 1e5 + 10;

struct SEG{
	int l, r, len;
	char ch;
};

struct node{
	int l, r;
	SEG maxl, maxr, maxn;
}tr[N << 2];

int n, m;
string a;

SEG max(SEG& a, SEG& b)
{
	if (a.len == b.len)	return a.l < b.l ? a : b;
	return a.len > b.len ? a : b;
}

void pushup(node& u, node& l, node& r)
{
	u.maxl = l.maxl;
	if (l.maxl.r == l.r && l.maxl.ch == r.maxl.ch)
	{
		u.maxl = {l.maxl.l, r.maxl.r, r.maxl.r - l.maxl.l + 1,l.maxl.ch};
	}
	u.maxr = r.maxr;
	if (r.maxr.l == r.l && r.maxr.ch == l.maxr.ch)
	{
		u.maxr = {l.maxr.l, r.maxr.r, r.maxr.r - l.maxr.l + 1,r.maxr.ch};
	}
	u.maxn = max(l.maxn, r.maxn);
	if (l.maxr.ch == r.maxl.ch)
	{
		SEG t = {l.maxr.l, r.maxl.r, r.maxl.r - l.maxr.l + 1, l.maxr.ch};
		u.maxn = max(u.maxn, t);
	}
}

void pushup(int u)
{
	pushup(tr[u], tr[u << 1], tr[u << 1 | 1]);
}

void build(int u, int l, int r)
{
	if (l == r)
	{
		tr[u] = {l, r, {l, r, 1, a[l]}, {l, r, 1, a[l]}, {l, r, 1, a[l]}};
		return;
	}
	tr[u] = {l, r};
	int mid = l + r >> 1;
	build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
	pushup(u);
}

void modify(int u, int x, char ch)
{
	if (tr[u].l == x && tr[u].r == x)
	{
		tr[u] = {x, x, {x, x, 1, ch}, {x, x, 1, ch}, {x, x, 1, ch}};
		return;
	}
	int mid = tr[u].l + tr[u].r >> 1;
	if (x <= mid)	modify(u << 1, x, ch);
	else	modify(u << 1 | 1, x, ch);
	pushup(u);
}

node query(int u, int l, int r)
{
	if (tr[u].l >= l && tr[u].r <= r)	return tr[u];
	int mid = tr[u].l + tr[u].r >> 1;
	if (r <= mid)	return query(u << 1, l, r);
	if (l > mid)	return query(u << 1 | 1, l ,r);
	node left = query(u << 1, l, r), right = query(u << 1 | 1, l, r), res;
	pushup(res, left, right);
	return res;
}

int main()
{
	cin >> n >> m >> a;
	a = " " + a;
	build(1, 1, n);
	while (m -- )
	{
		int op;
		cin >> op;
		if (op == 1)
		{
			int l, r;
			cin >> l >> r;
			node ans = query(1, l, r);
			cout << ans.maxn.l << " " << ans.maxn.r << endl;
		}
		else
		{
			int x;
			char ch;
			cin >> x >> ch;
			modify(1, x, ch);
		}
	}
	return 0;
}

1392 睡美人

题目描述:
  王子终于来到了熟睡的公主的身边了,只需要亲吻公主就可以成功唤醒公主。但是邪恶的巫婆在公主身上盖了很多魔毯,魔毯有红蓝两种颜色王子需要移除所有的魔毯才能亲吻公主,现在王子手里有三瓶魔法药水(都必须使用且只能使用一次),1号药水可以随机改变原来魔毯的覆盖顺序(有可能不发生改变),2号药水可以合并所有相邻且颜色相同的魔毯为一条魔毯,3号药水可以恰好(大于或小于m都无法移除)移除m个魔毯,药水需要按照编号为1、2、3的顺序使用。用0表示红色魔毯1表示蓝色魔毯,例如一开始魔毯顺序为"0101"、m=3,经过1号药水随机变换后顺序可能为"1001",使用2号药水后序列变为"101",最后使用3号药水恰好可以移除所有魔毯,这称之为一种移除成功的可能反之称之为一种移除失败的可能。
 现在王子想知道移除成功和移除失败的可能数分别为多少,结果可能很大需要对1e9+7取模。

输入:
第一行两个正整数n、m分表示魔毯的数量和3号药水恰好移除的魔毯数。
第二行个只包含0和1的字符串s。
(输入保证红色魔毯和蓝色魔毯都至少存在一条)
(2<=n<=1e6, 1<=m<=1e9)

输出
两个非负整数,分别表示移除成功和移除失败的可能数

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int mod=1e9+7;
const int N=1e6+10;
int n,m;
string s;
LL num1[N],num2[N];//num1储存范围内所有数字的阶乘,num2储存范围内所有数字的阶乘的逆元
LL qmi(LL x,LL y)//快速幂
{
    LL sum=1;
    while(y)
    {
        if(y&1)sum=(sum*x)%mod;
        y>>=1;
        x=x*x%mod;
    }
    return sum;
}
void init()//初始化num1,num2
{
    num1[0]=num2[0]=1;
    for(int i=1;i<=n;i++)
    {
        num1[i]=num1[i-1]*i%mod;
        num2[i]=qmi(num1[i],mod-2);//费马小定理求逆元
    }
}
LL C(int x,int y)//求组合数
{
    if(x-y<0)return 0;
    return num1[x]*num2[y]%mod*num2[x-y]%mod;
}
int main()
{
    cin>>n>>m>>s;
    init();
    int sum1=0,sum2=0;//sum1储存0的个数,sum2储存1的个数
    for(int i=0;i<n;i++)s[i]=='0'?++sum1:++sum2;
    if(sum1<sum2)swap(sum1,sum2);
    int sum=sum2*2+(sum1==sum2?0:1);//sum为在使用完2号魔药后最多可以保留的魔毯数
    LL res=C(n,sum2);//使用完一号药水后所有可能的组合情况
    if(sum<m||m==1)cout<<0<<" "<<res;//不存在移除的可能,题目保证0和1至少出现一次所以m至少为2
    else
    {
        LL ans=0;
        int x=m/2,y=m/2;
        if(m&1) ans=(C(sum1-1,x)*C(sum2-1,y-1)+(ans+C(sum1-1,y-1)*C(sum2-1,x)))%mod;//m为奇数,隐含了x--
        else ans=(C(sum1-1,x-1)*C(sum2-1,y-1)*2)%mod;//m为偶数
        cout<<ans<<" "<<(res-ans+mod)%mod;
    }
    return 0;
}

1393 最短距离

题目描述:
给定一棵包含 n 个顶点的树 T,以及 m 个查询请求。每个查询包含三个参数:x、y 和 k。其中 x 和 y 是树中的两个顶点,k 是一个整数。对于每个查询,你需要计算树中所有顶点到从 x 到 y 的简单路径上的最近距离恰好为 k 的顶点数量。

输入:
第一行,两个正整数n和m。(1 ≤ \leq n,m ≤ \leq 1e5)
接下来n-1行,每行两个正整数x,y。点x和点y之间有一条边。(1 ≤ \leq x,y ≤ \leq n)
最后m行,每行三个正整数x,y,k。(1 ≤ \leq x,y ≤ \leq n,1 ≤ \leq k ≤ \leq 100)

输出
对于每次询问,输出一个整数作为答案
每个答案占一行

#include <bits/stdc++.h>
using namespace std;
vector<int>num[100010];
int deep[100010],st[20][100010];        
int down[100010][110],up[100010][110];
void dfs(int x,int fa){
    deep[x]=deep[fa]+1;st[0][x]=fa;
    for(int i=1;i<=19;i++)
    st[i][x]=st[i-1][st[i-1][x]];
    down[x][0]=1;
    for(auto i:num[x])if(i!=fa){
        dfs(i,x);
        for(int j=0;j<100;j++)
        down[x][j+1]+=down[i][j];
    }
}
void dfs1(int x,int fa){
    for(int j=0;j<=100;j++)
    down[x][j]+=down[fa][j];
    for(auto i:num[x])if(i!=fa){
        up[i][1]=1;
        for(int j=1;j<100;j++)
        up[i][j+1]=(down[x][j]-down[fa][j])+up[x][j]-down[i][j-1];
        dfs1(i,x);
    }
}
int lca(int x,int y){
    if(deep[x]<deep[y])
    swap(x,y);
    int h=deep[x]-deep[y];
    for(int i=19;i>=0;i--)
    if(h>=(1<<i))h-=1<<i,x=st[i][x];
    if(x==y)return x;
    for(int i=19;i>=0;i--)
    if(st[i][x]!=st[i][y])
    x=st[i][x],y=st[i][y];
    return st[0][x];
}
int main(){
    int n,t;scanf("%d%d",&n,&t);
    for(int i=1;i<n;i++){
        int x,y;scanf("%d%d",&x,&y);
        num[x].push_back(y);
        num[y].push_back(x);
    }dfs(1,0);dfs1(1,0);
    while(t--){
        int x,y,k;
        scanf("%d%d%d",&x,&y,&k);
        int mid=lca(x,y);
        int ans=down[x][k]+down[y][k]-down[mid][k]-down[st[0][mid]][k];
        ans-=down[x][k-1]+down[y][k-1]-2*down[mid][k-1];
        ans+=up[mid][k];
        printf("%d\n",ans);
    }
}

1394 String Problem

题目描述:
  Little Z raised a question:
 Given a string S of length n containing only lowercase letters.
 You need to select several non-empty substrings of S so that they are disjoint pairwise, and each substring is a palindrome.
 Assuming you have selected K substrings(s1, s2…sk) that satisfy the above conditions, your score is the sum of the lengths of all substrings minus K. It is len(si) − K But Little Z is a dedicated person, and to increase difficulty, Little Z requires that each palindrome string contain at most one kind of letter
 Little Z wants you to find the maximum score.

输入:
A positive integer T in the first line represents the number of test groups, for each group of test data: The only line contains a string of length n which containing only lowercase letters. T ≤ 20, ∑n ≤ 106

输出
For each test data, print a number representing the maximum score

#include <bits/stdc++.h>
#include <cstdio>
#define N 2000010
#define rep(i, l, r) for (int i = (l); i <= (r); ++(i))
#define cmax(a, b) a = max(a, b)
#define cmin(a, b) a = min(a, b)
using namespace std;

char s[N];

void solve() {
  scanf("%s", s + 1);
  int n = strlen(s + 1);
  vector<pair<char, int>> v;
  v.push_back({s[1], 1});
  rep(i, 2, n) {
    if (s[i] == v.back().first)
      ++v.back().second;
    else
      v.push_back({s[i], 1});
  }
  int ans = 0;
  for (auto [x, y] : v)
    ans += y - 1;
  printf("%d\n", ans);
}

int main() {
  int T;
  scanf("%d", &T);
  while (T--) {
    solve();
  }
  return 0;
}

1395 Binary Number

题目描述:
  BLUE is learning binary numbers. There is an easy problem in his homework.
 You are given a binary number s1∼n (s1 is the highest bit. sn is the lowest bit.). You need to do an operation exactly k times: select an interval [l, r] (1 ≤ l ≤ r ≤ n) arbitrarily and flip sl , sl+1, …, sr, in other word, for all i ∈ [l, r], si becomes 1 if si is 0, si becomes 0 if si is 1. What is the biggest result binary number after the k operations.
 BLUE found useless algorithms useless on the problem, so he asked ACMZYX to help. ACMZYX looked down on the problem but finally got WA (wrong answer). Can you help them to find the correct solution?

输入:
 The first line of the input contains a single integer T (1 ≤ T ≤ 6 × 104 ), indicating the number of test cases
 In each test case:
 The first line contains two integers n, k. (1 ≤ n ≤ 105 , 0 ≤ k ≤ 1018)
 The second line contains a binary number s1∼n. (s1 = 1, ∀i ∈ [2, n] : si ∈ {0, 1})
 It’s guarenteed that in all test cases, ∑n ≤ 2.5 × 106

输出
You need to print a string of length n in one line, representing the biggest binary number after the k operations.

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n;
long long k;
char s[N];
void work(){
	scanf("%d%lld%s",&n,&k,s+1);
	if(n==1){
		if(k&1)puts("0");
		else puts("1");
		return;
	}
	bool f1=1;
	for(int i=1;i<=n;++i){
		if(s[i]=='0'){
			f1=0;break;
		}
	}
	if(f1){
		if(k==1){
			s[n]='0';
			printf("%s\n",s+1);
			return;
		}
	}
	long long cnt=k;
	for(int i=1;i<=n;++i){
		int j=i;
		while(j+1<=n&&s[j+1]==s[j])++j;
		if(cnt&&s[i]=='0'){
			for(int k=i;k<=j;++k)s[k]='1';
			--cnt;
		}
		i=j;
	}
	printf("%s\n",s+1);
}
int main(){
	int T;scanf("%d",&T);
	while(T--)work();
}

1396 Card Game

题目描述:
  Recently, playing card games has become popular. BLUE and ACMZYX are also playing a game. In this game, the cards must be placed in piles. Any number of cards can be stacked in the same pile. Any card can be placed at the bottom of an empty pile. The stacked cards go from the bottom to the top, with decreasing and consecutive values. For example, piles (5, 4, 3, 2, 1), (8, 7, 6, 5, 4, 3), (9), and () (an empty pile) are all valid, while piles (4, 2, 1) (not consecutive), (1, 2, 3) (not decreasing), and (9, 8, 7, 5, 6, 4, 3, 2) (neither consecutive nor decreasing) are not valid. (The description of the piles mentioned above is in the order from bottom to top).
 In one move, a player can choose a card from the top of a non-empty pile and move it to the top of another pile. Throughout the player’s moves, the stacking rules of the cards must be followed, otherwise it is considered a foul.
 BLUE is now playing the card game on a table with n piles, where one pile contains k cards (k, k − 1, k − 2, …, 2, 1), called pile 1, and the rest of the piles are empty piles. All the free slots are empty. BLUE wants to move all the cards from pile 1 to another pile (pile 2). At this point, clever ACMZYX comes up with a question:
Given the number of piles n, under the condition of not fouling, what is the maximum value of k that allows the movement of k cards as described above?
 Since the answer could be large, take the modulus of 998244353.

输入:
There are multiple test cases in this problem
The first line of input contains a positive integer t (1 ≤ t ≤ 1e5 ), indicating the number of test cases.
Afterwards, there are t test cases. Each test case consists of a single line containing an integer n (2 ≤ n ≤ 1e9 ), representing the number of piles.

输出
For each test case, output a single line containing an integer, representing the maximum value of k for the number of cards. Take the modulus of 998244353

#include <bits/stdc++.h>

using i64 = long long;

const int mod = 998244353;

long long quickpow(long long a, long long b) {
	long long res = 1;
	a %= mod;
	while (b) {
		if (b & 1)
			res = res * a % mod;
		b >>= 1;
		a = a * a % mod;
	}
	return res;
}

void solve() {
	int n;
	std::cin >> n;
	i64 ans = (quickpow(2, n - 1) - 1 + mod) % mod;
	std::cout << ans << '\n';
}

int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
	std::cout.tie(nullptr);
	int t = 1;
	std::cin >> t;
	while (t--) {
		solve();
	}
	return 0;
}

1397 宁宁的字符串

题目描述:
 对于一个小写字母而言,宁宁可以通过一次操作把这个字母变成相邻的字母。'a’和’b’相邻, 'b’和’c相邻,以此类推。特殊的, 'a’和’z’也是相邻的。可以认为,小写字母的相邻规则为一个环。
 宁宁拿到了一个仅包含小写字母的字符串,她想知道,使得所有字母都相等至少要多少次操作?

输入:
一个仅包含小写字母,长度不超过100000的字符串

输出
一个整数,代表最小的操作次数。

#include<bits/stdc++.h>

using namespace std;
const int lp=1e5+10;

int a[lp][27];
string v="abcdefghijklmnopqrstuvwxyz";

int main(){
    
    string s;
    cin>>s;
    
    for(int i=0;i<s.size();i++){
        
        for(int j=0;j<26;j++){
            int u=abs(s[i]-v[j]);
            a[i][j]=min(u,26-u);
        }
               
    }
    
    
    int cnt=0x3f3f3f3f,p=-1;
    for(int j=0;j<26;j++){
        int sum=0;
        for(int i=0;i<s.size();i++){
            sum+=a[i][j];
        }
        if(cnt>sum){
            cnt=sum;
            p=j;
        }
        
    }
    cout<<cnt;    
    
    
    return 0;
}

1398 宁宁的矩阵权值

题目描述:
宁宁定义一个矩阵权值为:每—对相邻元素之和的总和。例如,对于矩阵:
1 2
3 4
它的权值是(1+2)+(1+3)+(2+4)+(3+4)=3+4+6+7=20。
宁宁希望你构造一个n * n的矩阵,矩阵中的元素为1到n2且每个数恰好出现一次。她希望最终矩阵的权值尽可能大。你能帮帮她吗?由于矩阵可能过大,你不需要输出最终的矩阵,只需要输出这个最大权值即可。答案对1e9+7取模。

输入:
一个正整数n。2≤n <109

输出
矩阵的最大权值,对1e9+7取模。

#include<bits/stdc++.h>
#define int long long 

using namespace std;
const int mod=1e9+7;

int sum(int l){
    l=l%mod;
    return l*(l+1)/2%mod;
}

signed main(){
    
    int n;
    cin>>n;
    
    int m=n*n-(n-2)*(n-2);
    
    int res=(sum(n*n)-sum(m)+mod)%mod*4%mod;
    res=res+sum(m)*3%mod-10;
    cout<<(res+mod)%mod;
    
    return 0;
}


1399 宁宁的水果大礼包

题目描述:
宁宁有n个苹果,m个桃子。她可以把2个苹果和1个桃子组成价值a元的一号水果大礼包,也可以把1个苹果和2个桃子组成价值b元的二号水果大礼包。宁宁想知道,自己最多能组成多少价值总和的大礼包?

输入:
四个正整数n , m, a, b,用空格隔开。分别代表苹果的数量、桃子的数量、一号大礼包价值、二号大礼包价值。
1 ≤n, m, a,b ≤1e6

输出
一个整数,代表大礼包的最大价值总和。

#include<bits/stdc++.h>
#define int long long
using namespace std;

signed main(){
    
    int n,m,a,b;
    cin>>n>>m>>a>>b;
    
    int res=0;
    int num=min(n/2,m);
    
    for(int i=0;i<=num;i++){
        int x=i*a;
        x+=min(n-2*i,m-i>>1)*b;
        res=max(x,res);
    }
    
    cout<<res;
    
    
    return 0;
}

1400 翻转

题目描述:
给定一个长度为n的序列 a 1 a_1 a1 , a 2 a_2 a2, … . , a n a_n an 。保证此序列是一个1~n的排列。
请你找到一个合理的翻转区间[l,r],要求:
1.1≤l <r ≤n
2.将a~ a进行翻转后,整个序列恰好按1~n的顺序排列。
例如,对于序列1 6 5 4 3 2 7 8,我们可以选择翻转区间[2,6],将序列中第2~6个元素进行翻转后
得到
序列1 2 3 4 5 6 7 8,此时序列恰好按1~8的顺序排列

输入:
第一行包含整数n。
第二行包含n个整数a1, a2,… . , an输出格式

输出
如果找不到合理的翻转区间1, r],则输出0 0。
如果能找到合理的翻转区间[1,r],则输出 l 和 r 。

#include<bits/stdc++.h>

using namespace std;
const int lp=1e4;

int main(){
    
    int n;
    cin>>n;
    
    int l=0,r=0;
    int a[lp];
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    
    for(int i=1;i<=n;i++){
        if(a[i]!=i){
            l=i;
           break;
        }
        
    }
    
    for(int i=n;i>=1;i--){
        if(a[i]!=i){
            r=i;
            break;
        }
    }
    
    int p=l;
    for(int i=r;i>=l;i--){
        if(a[i]!=p ){
            cout<<"0 0";
            return 0;
        }
        
        p++;
    }
    
    cout<<l<<' '<<r;
    
    
    return 0;
}





1401 排列

题目描述:
已知,a1 , a2, . . . , an是1~n的全排列中字典序第k个排列。
请你判断,一共有多少个整数x同时满足以下所有条件:
1.1≤x≤n
2.x 的十进制表示不含4和7以外的数字。
3.ax的十进制表示不含4和7以外的数字。

输入:
共一行,包含两个整数n, k。

输出
如果1~n的全排列中字典序第k个排列根本不存在,则输出-1。
否则,输出一个整数,表示满足条件的x 的数量。

#include<bits/stdc++.h>
// #define int long long 

using namespace std;

int l,k;
bool st[15];
int ans;

int check(int n){
    int sum=1;
    for(int i=1;i<=n;i++){
        sum*=i;
        if(sum >= k) return k+1;
    }
    return sum;
}

bool opa(int u){
    while(u){
        int k=u%10;
        u/=10;
        if(k!=4 && k!=7) return false;
    }
    return true;
}

int get(int x){
    
    int p=0;
    while(check(p) <=k ) p++;
    //找到一定包含k组排列的开头,k是从后往前找的最多12(因为k<=1e9,而12!>1e9 这说明,只有最后12位是排列过的,前l-p是不用排列的)
    
    if(x<=l-p) return x;//如果说x是在该位置之前,则x==i(位置对应该位置的值)
    
    memset(st,0,sizeof st);
    int rank=k;
    for(int i=l-p+1;i<=l;i++){//枚举后几位
    //循环存在的意义:存在当  l-p+1 <= i < (一个值)  时,总满足:rank <= t 此时如果没有此层循环,会不断的返回已经排过位置的值 
        for(int j=1;j<=p;j++){//设置st从1开始记位数,防止数组开的过大
            if(!st[j]){//如果当前没有访问过
                int t=check(l-i);//计算第i位之后的全排列个数
                // int t=check(l-x);
                if(rank<=t){//如果说该位置满足条件
                    
                    if(x==i) //如果是该位置,直接返回要排列的值
                        return j+l-p;//如果说当前的位置是要找的位置
                    
                    //当该位置不是要找的位置,标记当前的值已经放过了
                    st[j]=1;
                    break;
                    
                }
                else rank-=t;
                
            }
        }
    }
    
}

void dfs(long long x){
    if(x>l) return ;
    
    if(x>0 && opa(get(x))) ans++;
    
    dfs(x*10+4);//只搜有4和7的位置
    dfs(x*10+7);
    
}



int main()
{
    
    
    cin>>l>>k;
    
    if(check(l)<k) cout<<-1;
    else{
        dfs(0);
        cout<<ans;
    }
    
    
    
    return 0;
}

1402 a-b Problem

题目描述:
  Alice and Bob are playing a little game. There are n stones. Alice and Bob take turns picking stones, with Alice going first. Each person can only pick one stone at a time until all the stones are gone. Each stone has two attributes, Ai and Bi . When Alice picks a stone, she earns Ai points, and when Bob picks a stone, he earns Bi points. The total score for each person is the sum of the points they earn when picking a stone. Both players want to maximize the difference between their scores, aiming to have their own score minus the opponent’s score as large as possible. The question is, what is the final result of Alice’s score minus Bob’s score?

输入:
The first line contains a positive integer, T, representing the number of test cases, where 1 ≤ T ≤ 20.
Next, for each test case, the following format is repeated: The first line contains a positive integer, n, where 1 ≤ n ≤ 1e5 .
The next n lines contain two integers, Ai and Bi , representing the two attributes of the ith stone. The values of Ai and Bi satisfy 0 ≤ Ai , Bi ≤ 1e9

输出
For each test case, output one line containing an integer representing the answer.

#include<stdio.h>
#include<algorithm>

struct Z
{
    int a,b;
    int operator<(Z o) const
    {
        return a+b>o.a+o.b;
    }
};
Z z[100001];

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n;
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            scanf("%d%d",&z[i].a,&z[i].b);
        std::sort(z,z+n);
        long long sum=0;
        for(int i=0;i<n;i++)
        {
            if(i&1)sum-=z[i].b;
            else sum+=z[i].a;
        }
        printf("%lld\n",sum);
    }
    
}

1403 PSO

题目描述:
  Particle swarm optimization ( PSO ) is a population-based stochastic optimization algorithm. In addition to the basic structure of PSO, there is also a variant called star-topology PSO, which introduces a star-shaped communication structure among particles. In this structure, there is a central particle called the leader, which is responsible for gathering and disseminating information to the rest of the particles in the swarm.
 Now there are n particles on the star-topology. Among the n particles, there is one particle as the leader, and there is an edge between the other particles and the leader. For a piece of information, it can be propagated along an edge on the topology.
 To examine the benefits of this topology, we need to calculate the following data:
  We define that X is number of edges required for them to exchange information for two different particles. Please calculate the expected value rounded off and maximum value of X.

输入:
The first line of input is a positive integer T(T ≤ 1e5 ) representing the number of test cases. For each line,input a number n(2 ≤ n ≤ 1e9 ).

输出
For each case, output two floating-point numbers representing the he expected value and maximum value of X. (keep 9 decimal places)

#include<bits/stdc++.h>
using namespace std;
int n;
double p;
void solve(){
    scanf("%d",&n);
    printf("%.9lf ",2-2.0/n);
    if(n==2)printf("1.000000000\n");
    else printf("2.000000000\n");
}
int main(){
    int T;
    scanf("%d",&T);
    while(T--)
        solve();
    return 0;
}

1404 入门mex

题目描述:
mex在许多题目中都有所考察,本题就来带大家入门mex
我们规定一些数字的mex是指满足下列要求的数字x
1、对于所有0≤y <,y都在这些数字里出现过
2、x没有在这些数字里出现过
例如{1,2,3}的mex是0,{0,1,2,3,6,5}的mex是4
你也可以这样理解,一些数字的mex是从0往上枚举,第一个没出现的数字。
现在给你大小为n的数组a,请你回答选最多k个数字,mex最大是多少?

输入:
第一行两个整数n和k
接下来一行n个数字表示数组a.
1≤k ≤n ≤1e5,0 ≤ai≤1e9

输出
输出一行一个整数表示你的答案

#include<bits/stdc++.h>

using namespace std;

int main(){
    
    int n;
    cin>>n;
    
    int k;
    cin>>k;
    
    int a[n+10];
    set<int> sa;
    for(int i=1;i<=n;i++) {
        int x;
        cin>>x;
        sa.insert(x);
    }
    int i=0;
 for(auto x:sa){
//      cout<<x<<' ';
     if(x!=i || k==0){
         cout<<i;
         return 0;
     }
     i++;
     k--;
 }
    
    cout<<n;
    
    return 0;
}

1405 完全平方数

题目描述:
给定n个数,求其中完全平方数的个数。
数字x是完全平方数等价于存在整数y,使得y*y=x

输入:
第一行一个整数n 。
第二行n个整数a1, a2 ,…, an
数据保证1≤ai, n <=10000。

输出
一行一个整数表示序列中完全平方数的个数。

#include <iostream>
#include <cmath>

using namespace std;

bool check(int x)
{
    int a = sqrt(x);
    
    return a * a == x;
}

int main()
{
    int t, x, ans = 0;
    scanf("%d",&t);
    
    while(t --)
    {
        scanf("%d",&x);
        
        if(check(x)) ans ++;
    }
    
    printf("%d", ans);
}

1406 x(简单版本)

题目描述:
给定整数序列a1,…, an 。
求一个最小的非负整数x,使得序列a的任意子集和不等于x。
任意子集包含空集和全集。
数据保证1≤n<=1e5,1≤ai<=2*1e9

输入:
第一行一个正整数n
接下来一行n个整数表示序列a里的数字

输出
输出一个整数表示你的答案x

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int read()
{
	int x;scanf("%d",&x);return x;
}
int n,a[100010];
ll ans;
int main()
{
	n=read();
	assert(1<=n&&n<=100000);
	for(int i=1;i<=n;i++)
	{
		a[i]=read();
		assert(1<=a[i]&&a[i]<=2000000000);
	}
	sort(a+1,a+1+n);
	ans=0;
	for(int i=1;i<=n;i++)
		if(a[i]-1<=ans)
			ans+=a[i];
		else break;
	cout<<ans+1;
}


1407 找最大值

题目描述:
给定n个数,求其中奇数的的最大值。

输入:
第一行一个整数n 。
第二行n个整数a1, a2,…, an
数据保证1≤ai, n<=10000。

输出
一行一个整数表示序列中奇数的最大值。

#include<bits/stdc++.h>

using namespace std;

int main(){
    
    int n;
    cin>>n;
    
    int m=0;
    for(int i=1;i<=n;i++){
        int x;
        cin>>x;
        
        if(x%2) m=max(x,m);
    }
    cout<<m;
    return  0;
}

1408 替换大师

题目描述:
作为一个替换大师,你接到了一个新的任务。
首先将会给你一个长为n的字符串,字符串内有若干个左括号"(‘和若干个右括号’)‘,还有很多小写字母。当然,还有很多逗号’,‘。
你的任务是将每一对左右括号内部的逗号’,‘换成句号’.',数据保证不会存在类似(a(b)c)这样的括号镶嵌,只会存在()()()()这样的。

输入:
第一行一个正整数n表示字符串长度,保证1≤n ≤105
第二行一个只包含逗号、左右括号、小写字母的字符串
数据保证不会出现类似(a (b)c)的括号镶嵌,只会出现d (a)(b)©这样的并列括号,且保证括号是匹配的,不会出现) k(的情况

输出
输出一个只包含句号、逗号、左右括号、小写字母的字符串表示你的答案。

#include<bits/stdc++.h>

using namespace std;

int main(){
    
    int n;
    cin>>n;
    string s;
    cin>>s;
    
    int u=1,l=0,r=0;
    for(int i=0;i<n;i++){
        
        if(s[i]=='(') l++;
        
        if(s[i]==')') l--;
        
        if(l && s[i]==','){
            cout<<'.'; 
            continue;
        }
        
        cout<<s[i];
    }
    
    return 0;
    
}

1409 泰拉瑞亚

题目描述:
出题人在玩泰拉瑞亚时,构想了一种新型回旋镖,打算让你用它们打一个血量为h的boss
你手里有n把这样的回旋镖,每个回旋镖有两种攻击方式
—种是打出去再飞回手里,会造成ai点伤害。这样你可以接着使用
另一种是倾尽全力打出去回不来了,将会造成bi点伤害。倾尽全力打出的bi点伤害将会大于等于ai,但是这样就不能再使用这把回旋镖了
当怪物血量小于等于0时你可以获得胜利,虽说一直用同一把回旋镖也能获得胜利,但是你还是希望最小化次数。请你输出在最优安排下获得胜利的最小次数。

输入:
出题人在玩泰拉瑞亚时,构想了一种新型回旋镖,打算让你用它们打一个血量为h的boss
你手里有n把这样的回旋镖,每个回旋镖有两种攻击方式
—种是打出去再飞回手里,会造成ai点伤害。这样你可以接着使用
另一种是倾尽全力打出去回不来了,将会造成bi点伤害。倾尽全力打出的bi点伤害将会大于等于ai,但是这样就不能再使用这把回旋镖了
当怪物血量小于等于0时你可以获得胜利,虽说一直用同一把回旋镖也能获得胜利,但是你还是希望最小化次数。请你输出在最优安排下获得胜利的最小次数。

输出
一行一个正整数表示获取胜利需要最少多少次攻击

#include<bits/stdc++.h>
// #define int long long

using namespace std;
const int lp=1e5+10;

int a[lp],b[lp];

signed main(){

    int n,k;
    cin>>n>>k;
    
    for(int i=1;i<=n;i++){
        cin>>a[i]>>b[i];
    }
    
    sort(a+1,a+n+1,greater());
    sort(b+1,b+n+1,greater());
    
    int cnt=0;
    for(int i=1;b[i]>a[1] && k>0;i++){
        cnt++;
        k-=b[i];
    }
    
    if(k<=0) cout<<cnt;
    else cout<<cnt+(k+a[1]-1)/a[1];
    
    
    
    
    return 0;
}

1410 计数问题

题目描述:
首先,出题人将给你一个正整数n
其次,你需要给出有多少种方案,使得A、B、C、D四个数字都是正整数且A*B+C*D=n
两个方案不同当且仅当A、B、C、D至少有一个数字不同,例如1*1+3*1和1*1+1*3是不同的两个方案
可以证明,1<n ≤1e5时答案小于等于9* 1e18,所以不需要取余

输入:
一行一个正整数n,保证1≤n≤1e5

输出
输出一个整数表示你的答案

#include<bits/stdc++.h>

using namespace std;
// #define int long long


int opa(int k){
    int sum=0;
    for(int i=1;i<=k/i;i++){
        if(k%i==0){
            sum++;
            if(k/i!=i) sum++;
        } 
    }
    return sum;
}

signed main(){
    int n;
    cin>>n;
    int cnt=0;
    for(int i=1;i<=n;i++){
        int a=opa(i),b=opa(n-i);
//         cout<<a<<' '<<b<<endl;
        cnt+=a*b;
    }
    cout<<cnt;
    return 0;
}

1411 AND and SUM

题目描述:
给定两个整数a和s,问是否存在两个非负整数满足:
x & y = a
x + y = s
如果存在,输出Yes,如果不存在输出No
因为本题比较简单,数据给了多次查询。

输入:
第一行一个整数T,表示查询次数。
接下来T行,每行两个整数:a和s。
数据保证1≤T≤1e5,0≤a,s ≤ 2 60 2^{60} 260

输出
T行,每行按要求输出Yes或者No

#include<bits/stdc++.h>
#define int long long
using namespace std;

void opa(int a,int s){
    int d=s-2*a;
    if( d<0 || (d & a)){
        cout<<"No"<<endl;
        return ;
    }
    cout<<"Yes"<<endl;
}

signed main(){
    int n;
    cin>>n;
    
    while(n--){
        int x,y;
        cin>>x>>y;
        opa(x,y);
    }
    return 0;
}

1412 数学题

题目描述:
给出n,x,请你输出这个式子的值对998244353取余
sum= ∏ i = 0 n \prod_{i=0}^ n i=0n (1+ x ( 2 i ) x^{({2^i}) } x(2i) )

输入:
输入一行两个整数n和x
保证0≤n≤1e18,1 ≤a≤1e18

输出
输出式子的值对998244353取余的结果

#include<bits/stdc++.h>
using namespace std;
//#define int long long
#define ll long long
// const int mod=1e9+7;
const int mod=998244353;
const int N=1e6+10;
ll q_pow(ll a,ll b)
{
	ll t=1;
	while(b)
	{
		if(b&1)t=t*a%mod;
		b>>=1;
		a=a*a%mod;
	}
	return t;
}
ll q_pow(ll a,ll b,ll c)
{
	ll t=1;
	while(b)
	{
		if(b&1)t=t*a%c;
		b>>=1;
		a=a*a%c;
	}
	return t;
}
void solve()
{
    ll n,x;
    cin>>n>>x;
    x%=mod;
    ll k=q_pow(2,n+1,mod-1);
    if(x==1)
    {
        cout<<q_pow(2,n+1)<<endl;
    }
    else if(x==0)
    {
        cout<<1<<endl;
    }
    else
    {
        ll s=q_pow(x,k)-1+mod;
        s%=mod;
        cout<<s*q_pow(x-1,mod-2)%mod;
    }
}
signed main()
{
	int t;
// 	cin>>t;
    t=1;
	while(t--)solve();
}



1413 真 · x(困难版本)

题目描述:
给定整数序列a1,…, an 。
m次询问,每次给定L,R求一个最小的非负整数x,使得序列al,

的任意子集和不等于x。
数据保证1≤n, m≤4×1e4,1≤ai,y≤109,1≤L<R≤n,1 ≤k ≤n

输入:
第一行2个整数n, m 。
接下来1行n个整数表示ai。
接下来m行,每行第一个整数opt
-若opt = 1 ,接下来2个整数k, y表示令ak=y
-若 opt = 2,接下来 2个整数L,R表示一次查询操作

输出
若干行每行一个整数,对应一次查询操作的答案

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int inf=1<<30;
int n,m,a[40010],mi[40]={0,1},Lbel,Nbel;
LL sum[31],ans;int minn[31];
struct SegmentTree
{int l,r,min[31];LL data[31];}st[160010];
inline int read()
{
	int x=0;bool w=0;char ch=0;
	while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return w?-x:x;
}
inline int getbel(int x)
{
	if(x==1)return 1;
	int temp=1,l=1,r=30,mid;
	while(l<=r){
		mid=(l+r)>>1;
		if(x>=mi[mid])temp=mid,l=mid+1;
		else r=mid-1;
	}
	return temp;
}
void build(int p,int l,int r)
{
	st[p].l=l;st[p].r=r;
	if(l==r){
		int Bel=getbel(a[l]);
		for(int i=1;i<=30;i++)st[p].min[i]=inf;
		st[p].data[Bel]=st[p].min[Bel]=a[l];
		return;
	}
	int mid=(l+r)>>1;
	build(p<<1,l,mid);
	build(p<<1|1,mid+1,r);
	for(int i=1;i<=30;i++){
		st[p].data[i]=st[p<<1].data[i]+st[p<<1|1].data[i];
		st[p].min[i]=min(st[p<<1].min[i],st[p<<1|1].min[i]);
	}
}
void change(int p,int pos,int k)
{
	if(st[p].l==st[p].r){
		st[p].data[Lbel]=0;st[p].min[Lbel]=inf;
		st[p].data[Nbel]=st[p].min[Nbel]=k;
		return;
	}
	int mid=(st[p].l+st[p].r)>>1;
	if(pos<=mid)change(p<<1,pos,k);
	else change(p<<1|1,pos,k);
	st[p].data[Lbel]=st[p<<1].data[Lbel]+st[p<<1|1].data[Lbel];
	st[p].min[Lbel]=min(st[p<<1].min[Lbel],st[p<<1|1].min[Lbel]);
	st[p].data[Nbel]=st[p<<1].data[Nbel]+st[p<<1|1].data[Nbel];
	st[p].min[Nbel]=min(st[p<<1].min[Nbel],st[p<<1|1].min[Nbel]);
}
void calc(int p,int l,int r)
{
	if(l<=st[p].l&&st[p].r<=r){
		for(int i=1;i<=30;i++){
			minn[i]=min(minn[i],st[p].min[i]);
			sum[i]+=st[p].data[i];
		}
		return;
	}
	int mid=(st[p].l+st[p].r)>>1;
	if(l<=mid)calc(p<<1,l,r);
	if(mid<r)calc(p<<1|1,l,r);
}
LL ask(int l,int r)
{
	memset(minn,0x3f,sizeof minn);
	memset(sum,0,sizeof sum);
	calc(1,l,r);
	ans=sum[1];
	for(int i=2;i<=30;i++)
	if(ans+1>=minn[i])ans+=sum[i];
	return ans+1;
}
int main()
{
	for(int i=2;i<=30;i++)mi[i]=mi[i-1]*2;
	n=read();m=read();
	assert(1<=n&&n<=40000);
	assert(1<=m&&m<=40000);
	for(int i=1;i<=n;i++){
		a[i]=read();
		assert(1<=a[i]&&a[i]<=1000000000);
	}
	build(1,1,n);
	while(m--){
		int opt=read(),l=read(),r=read();
		assert(opt==1||opt==2);
		if(opt==1)
		{
			assert(1<=l&&l<=n);
			assert(1<=r&&r<=1000000000);
		}
		else
			assert(1<=l&&l<=r&&r<=n);
		if(opt&1){
			Lbel=getbel(a[l]);Nbel=getbel(a[l]=r);
			change(1,l,r);
		}else printf("%lld\n",ask(l,r));
	}
}

1414 发工资咯

题目描述:
一个公司有n个人,每个月都要给这n个人发工资,刚开始每个人的工资都为0,每月底公司会进行两种操作。
1.挑一段连续的区间给区间内的人涨工资
2询问某个区间内的人迄今为止已经发了多少工资。
请你回答每个操作2

输入:
输入描述:
第一行输入n,q
1≤n≤2* 1e5,1≤q≤2* 1e5
接下来q行输入操作
分别是

0 l r w
表示l到r区间内的人本月涨了w元工资

1 l r
询问l,r内的人迄今为止发了多少钱

数据保证1≤l≤r ≤n,1 ≤w≤1e9

输出
每次询问发钱过后
输出一个整数,表示区间发过多少工资,并且取模998244353

#include <bits/stdc++.h>
using namespace std;
const int N=2e5+5;
#define ls k<<1
#define rs k<<1|1
// long long a[N];
const int mod=998244353;
struct node{
    int l,r;
    long long s,add,s1,add1;
}t[N<<2];
void PushUp(node& x,node& l,node& r){
	x.s=l.s+r.s;x.s%=mod;
    x.s1=l.s1+r.s1;x.s1%=mod;
}
void PushUp(int k){
	PushUp(t[k],t[ls],t[rs]);
}
void build(int k,int l,int r){
	if(l==r)t[k]={l,l};
	else{
		t[k]={l,r};
		int m=l+((r-l)>>1);
		build(k<<1,l,m);
		build(k<<1|1,m+1,r);
		PushUp(k);
	}
}
void PushDown(int k,int l,int r){
	if(t[k].add){
        int m=l+((r-l)>>1);
		t[ls].add+=t[k].add;t[rs].add+=t[k].add;
        t[ls].add%=mod;t[rs].add%=mod;
		t[ls].s+=t[k].add*(m-l+1)%mod;t[rs].s+=t[k].add*(r-m)%mod;
        t[ls].s%=mod;t[rs].s%=mod;
		t[k].add=0;
	}
    if(t[k].add1){
        int m=l+((r-l)>>1);
		t[ls].add1+=t[k].add1;t[rs].add1+=t[k].add1;
        t[ls].add1%=mod;t[rs].add1%=mod;
		t[ls].s1+=t[k].add1*(m-l+1)%mod;t[rs].s1+=t[k].add1*(r-m)%mod;
        t[ls].s1%=mod;t[rs].s1%=mod;
		t[k].add1=0;
	}
}
node Query(int L,int R,int l,int r,int k){
	if(L<=l&&r<=R)return t[k];
	else{
        PushDown(k,l,r);
		int m=l+((r-l)>>1);
		if(R<=m)return Query(L,R,l,m,k<<1);
		if(L>=m+1)return Query(L,R,m+1,r,k<<1|1);
        node res,left=Query(L,R,l,m,k<<1),right=Query(L,R,m+1,r,k<<1|1);
		PushUp(res,left,right);
		return res;	
	}
}
void Add(int L,int R,int v,int l,int r,int k){
	if(L<=l&&r<=R){
		t[k].add+=v;
        t[k].add%=mod;
		t[k].s+=1LL*v*(r-l+1)%mod;
        t[k].s%=mod;
	}
	else{
		PushDown(k,l,r);
		int m=l+((r-l)>>1);
		if(L<=m)Add(L,R,v,l,m,k<<1);
		if(R>=m+1)Add(L,R,v,m+1,r,k<<1|1);
		PushUp(k);
	}
}
void Ad(int L,int R,int v,int l,int r,int k){
	if(L<=l&&r<=R){
		t[k].add1+=v;
        t[k].add1%=mod;
		t[k].s1+=1LL*v*(r-l+1)%mod;
        t[k].s1%=mod;
	}
	else{
		PushDown(k,l,r);
		int m=l+((r-l)>>1);
		if(L<=m)Ad(L,R,v,l,m,k<<1);
		if(R>=m+1)Ad(L,R,v,m+1,r,k<<1|1);
		PushUp(k);
	}
}
void solve(void)
{
    int n,q;cin>>n>>q;
    build(1,1,n);
    for(int i=1;i<=q;i++){
        int op;
		cin>>op;
        if(op==0){
            long long l,r,w;cin>>l>>r>>w;
            Add(l,r,w,1,n,1);
            Ad(l,r,w*(i-1)%mod,1,n,1);
        }else{
            long long l,r;cin>>l>>r;
            node ans=Query(l,r,1,n,1);
            cout<<(ans.s*i%mod-ans.s1+mod)%mod<<'\n';
        }
    }
}
signed main(void)
{
    std::ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    // int t;
    // cin>>t;
    // while(t--)
    solve();
    return 0;
}

1415 她与灯

题目描述:
有n个灯排成一排,有的灯是开着的,有的灯是关着的。第i盏灯的开关状态是ai (1表示开,0表示关)。现在希望让第i盏灯的开关状态变成 bi。
有m个开关,第 i个可以翻转[li,ri]中的所有灯的开关状态(即1变成0,0变成1)。每种开关最多只能按一次。
你需要求出有多少种按开关的方案,使得所有灯都能够到达想要的状态。由于方案数可能很大,只需要输出答案对1e9+7取模的结果。

输入:
第一行共两个正整数n, m。
第二行一个长度为 n的01串,表示ai。
第三行一个长度为n的01串,表示 bi。
接下来 m行每行两个正整数li, ri,表示一个开关。保证1≤n ≤1e6, n ≤m≤2* n

输出
一个非负整数,表示方案数模1e9+7。

#include <iostream>
#include <map>
#include <set>
#include <vector>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <stack>
#include <algorithm>
#include <cmath>
#include <unordered_map>
#include <deque>
#include <bitset>
#define rep(i,z,n) for(int i = z;i <= n; i++)
#define per(i,n,z) for(int i = n;i >= z; i--)
#define PII pair<int,int>
#define fi first
#define se second
#define vi vector<int>
#define vl vector<ll>
#define pb push_back
#define sz(x) (int)x.size()
#define all(x) (x).begin(),(x).end()
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 1e6 + 10;
vector<int> g[N];
int v[N];
bool vis[N];
const ll mod = 1e9 + 7;
ll ksm(ll a,ll b)
{
    ll rs = 1;
    while(b) {
        if(b & 1) rs = rs * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return rs;
}
inline int dfs(int u)
{
    int cnt = v[u];
    vis[u] = true;
    for(auto c : g[u]) {
        if(vis[c]) continue;
        cnt += dfs(c);
    }
    return cnt;
}
void solve()
{
    int n,m;
    cin >> n >> m;
    string s,t;
    cin >> s >> t;
    s = " " + s,t = " " + t;
    for(int i = 1;i <= n;i ++) v[i] = (s[i] != t[i]);
    for(int i = n + 1;i >= 1;i --) v[i] ^= v[i - 1];
    for(int i = 1;i <= m;i ++) {
        int l,r;
        cin >> l >> r;
        r ++;
        g[l].pb(r),g[r].pb(l);
    }
    ll ans = 1,cc = m - n - 1;
    for(int i = 1;i <= n + 1;i ++) {
        if(vis[i]) continue;
        int cnt = dfs(i);
        if(cnt & 1) {
            cout << 0 << endl;
            return;
        }
        cc ++;
    }
    cout << ksm(2,cc) << '\n';
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    int T = 1;
    // cin >> T;
    while(T --) solve();
    return 0;
}

1416 Touhou Red Red Blue

题目描述:
You are playing a game called Touhou Red Red Blue.

In this game, you will receive n n n mini UFOs (Undefined Fantastic object) one by one, and you can decide to store or discard each UFO at the time you receive it. Each UFO has one of these three colors: R, G, and B.

You have two bags numbered 1 1 1 and 2 2 2, which are initially empty.

When you decided to store a UFO (marked as U U U ) and at least one bag is empty:

  • If bag 1 1 1 is empty, store U U U in bag 1 1 1.
    - If bag 1 1 1 is not empty and bag 2 2 2 is empty, store U U U in bag 2 2 2.

    When you decided to store a UFO (marked as U U U ) and no bag is empty, we consider the three UFOs we stored(the current one, the one in the bag 1 1 1 , and the one in the bag 2 2 2 ) :

  • If all three UFOs have the same color, these three UFOs will disappear and you get 1 1 1 point (this is the only way you can get points). After that, you will get an additional UFO (not in the given sequence) in your bag 1 1 1 , which color can be decided by yourself.

  • If all three UFOs have different colors with each other, these three UFOs will disappear. After that, you will get two additional UFOs (not in the given sequence) in your bag 1 1 1 and bag 2 2 2, and you can decide their colors independently by yourself.

  • Otherwise, you will discard the UFO in bag 1 1 1, move the UFO in bag 2 2 2 to bag 1 1 1, and store U U U in bag 2.

    What is the maximum points you can get after receiving all these n n n UFOs?

输入:
The first line contains one integer T   ( 1 ≤ T ≤ 10 ) T\ (1\le T\le 10) T (1T10) which represents the number of test cases.

For each test case:

One line contains one string S   ( 1 ≤ ∣ S ∣ ≤ 1 0 5 ) S\ (1\le |S|\le 10^5) S (1S105) consisting of uppercase letters ‘R’, ‘G’ and ‘B’, represents the color sequence of all the given UFOs.

输出
For each test case, print one line containing one integer which represents the most points you could get.

题解
简单 DP,定义 fi,a,b 表示考虑完前 i 个飞碟,手里先拿着 a 颜色,后拿着 b 颜色的最大分数。
把题目中的转移都考虑一下即可。

#include<stdio.h>
#include<algorithm>

struct Z
{
    int a,b;
    int operator<(Z o) const
    {
        return a+b>o.a+o.b;
    }
};
Z z[100001];

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n;
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            scanf("%d%d",&z[i].a,&z[i].b);
        std::sort(z,z+n);
        long long sum=0;
        for(int i=0;i<n;i++)
        {
            if(i&1)sum-=z[i].b;
            else sum+=z[i].a;
        }
        printf("%lld\n",sum);
    }
    
}

1417 Expectation (Easy Version)

题目描述:
Note: The only difference between the easy and hard versions is the range of n n n and m m m .
You are to play a game for n n n times. Each time you have the probability a b \frac ab ba to win.
If you win, you will get k m k^m km score, where k k k is the total times you win at that time, otherwise you won’t get any score.
Your final score is the sum of the score you get each time. For instance, if n = 5 , m = 10 n=5, m=10 n=5,m=10, and you win twice in total, your final score is 1 10 + 2 10 = 1025 1^{10} + 2^{10}=1025 110+210=1025.
Now you wonder the expectation of your final score modulo 998244353 998244353 998244353

输入:
The first line of the input contains an integer T   ( 1 ≤ T ≤ 20 ) T\ (1\le T \le 20) T (1T20), indicating the number of the test cases
The next T T T lines, each line has four integers n , m , a , b   ( 1 ≤ n ≤ 1 0 6 , 1 ≤ m , a , b < 998244353 ) n, m, a, b\ (1\le n\le 10^6, 1 \le m,a,b < 998244353) n,m,a,b (1n106,1m,a,b<998244353), indicating the number of games you play, the power of k k k is m m m, and the probatility to win a game is a b \frac ab ba.
It’s guaranteed that ∑ n ≤ 1 0 7 \sum n\le 10^7 n107.

输出
T T T lines, each line has one interger, indicating the answer.

题解
问题的关键在于对于任意 0 ≤ k ≤ n, 求出最终赢 k 次的概率。
假设每次赢的概率是 p, 则最后赢 k 次的概率就是 ( 1 + p x ) n (1 + px)^n (1+px)n 的第 k 项。

#include <bits/stdc++.h>
using i64 = int64_t;
using u32 = uint32_t;
using u64 = uint64_t;
const int N = 1 << 20;
const int P = 998244353;
struct mint {
    int x;
    constexpr mint(int x = 0) : x(x) {}
    mint operator-() const { return x > 0 ? P - x : 0; }
    mint operator+(mint o) const { return x + o.x < P ? x + o.x : x + o.x - P; }
    mint operator-(mint o) const { return x - o.x < 0 ? x - o.x + P : x - o.x; }
    mint operator*(mint o) const { return int(u64(x) * o.x % P); }
    mint &operator+=(mint o) { return *this = *this + o; }
    mint &operator-=(mint o) { return *this = *this - o; }
    mint &operator*=(mint o) { return *this = *this * o; }
    mint inv() const { return pow(P - 2); }
    mint cbrt() const { return pow((P + P - 1) / 3); }
    mint pow(auto k) const {
        mint a = x;
        mint b = 1;
        for (; k; k >>= 1) {
            if (k & 1)
                b *= a;
            a *= a;
        }
        return b;
    }
    mint sqrt() const {
        if (pow(P >> 1).x != 1) return 0;
        mint a = pow(60);
        mint b = pow(119);
        for (int k = 21; k >= 0; --k)
            if (b.pow(1 << k).x != 1) {
                a *= mint(3).pow(P >> (k + 2));
                b *= mint(3).pow(P >> (k + 1));
            }
        return std::min(a.x, P - a.x);
    }
};
mint w[N];
mint fac[N];
mint inv[N];
mint ivv[N];

void __attribute__((constructor)) init() {
    w[N / 2] = 1;
    mint g = mint(3).pow(P / N);
    for (int i = N / 2 + 1; i < N; ++i) w[i] = w[i - 1] * g;
    for (int i = N / 2 - 1; i > 0; --i) w[i] = w[i << 1];
    fac[0] = fac[1] = 1;
    inv[0] = inv[1] = 1;
    ivv[0] = ivv[1] = 1;
    for (int i = 2; i < N; ++i) fac[i] = fac[i - 1] * i;
    for (int i = 2; i < N; ++i) inv[i] = inv[P % i] * (P - P / i);
    for (int i = 2; i < N; ++i) ivv[i] = ivv[i - 1] * inv[i];
}
int main() {
#ifdef LOCAL
    auto flush = [&]() {};
    auto ii = [&]() {
        int x;
        std::cin >> x;
        return x;
    };
    auto oo = [&](auto x, char c = 10) {
        std::cout << x << c << std::flush;
    };
#else
    char bufI[1 << 19], *ptrI = bufI, *endI = bufI + sizeof(bufI);
    char bufO[1 << 19], *ptrO = bufO, *endO = bufO + sizeof(bufO);
    fread(bufI, 1, sizeof(bufI), stdin);
    auto load = [&]() {
        memcpy(bufI, ptrI, endI - ptrI);
        fread(endI - ptrI + bufI, 1, ptrI - bufI, stdin);
        ptrI = bufI;
    };
    auto flush = [&]() {
        fwrite(bufO, 1, ptrO - bufO, stdout);
        ptrO = bufO;
    };
    auto ii = [&]() {
        if (endI - ptrI < 32) load();
        int x{};
        int n{};
        for (; *ptrI < 48; ++ptrI) n = *ptrI == 45;
        for (; *ptrI > 47; ++ptrI) x = x * 10 + *ptrI - 48;
        return n ? -x : +x;
    };
    auto oo = [&](auto x, char c = 10) {
        if (endO - ptrO < 32) flush();
        if (x < 0) x = -x, *ptrO++ = '-';
        char buf[20];
        char *end = buf + 20;
        char *ptr = buf + 20;
        *--ptr = c;
        for (; x >= 10; x /= 10)
            *--ptr = char(48 + x % 10);
        *--ptr = char(48 + x);
        memcpy(ptrO, ptr, end - ptr);
        ptrO += end - ptr;
    };
#endif
    int T = ii();
    while(T--) {
        int n = ii();
        int m = ii();
        mint a = ii();
        mint b = ii();
        mint p = a * b.inv();
        mint q = -p + 1;
        mint r = p * q.inv();
        mint ans;
        mint sum;
        mint tmp = q.pow(n);
        for (int i = 1; i <= n; ++i) {
            sum += mint(i).pow(m);
            tmp *= r * inv[i] * (n - i + 1);
            ans += tmp * sum;
        }
        oo(ans.x);
    }
    flush();
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值