思路:二分
二分给出一个mid,让第一个数 r 为max(a[1]-d,0),以后的数至少是 r+1,而且太小就直接返回NO,也就是 if( a[i]+mid < r+1) return 0;
因为递增,r最小为 r+1。因为差值小于mid,r最小为 a[i]-mid ,所以 r=max(r+1,a[i]-mid);
int check(int d){
int r=max(0,a[1]-d); //题意给的是正整数,应该是max(1,a[1]-d),数据估计没卡这点
fo(2,n){
if(a[i]+d
总代码:
#include
#include
using namespace std;
#define fo(a,b) for(int i=a;i<=b;i++)
#define inf 0x3f3f3f3f
#define ll long long
#define M 1000005
int n;
int a[M];
int check(int d){
int r=max(0,a[1]-d);
fo(2,n){
if(a[i]+d>n;
fo(1,n) cin>>a[i];
int l=1,r=1e9,ans=-1;
while(l<=r){
int mid=(l+r)/2;
if(check(mid)){
r=mid-1;
ans=mid;
}
else l=mid+1;
}
cout<
思路: 树的dfs序+莫队
这题属实是没想到出个莫队,想到莫队的话难度不是很大,树遍历dfs序使一个点的子树成为连续的区间。
查询一个节点的子树值,就是查询一个连续区间的值,用普通莫队就可以做出,细节就不多说了,因为这里和莫队模板题很接近了
总代码:
#include
using namespace std;
#define fo(a,b) for(int i=a;i<=b;i++)
#define ll long long
#define int long long
#define M 400010
#define ll long long
int n,m,k,s=0,v,i,j;
int res=0;
struct Node
{
int id,l,r;
bool operator<(const Node temp)const{
if(l/v==temp.l/v) return r>v;
}xx[M];
int a[M],ans[M],vis[M];
int in[M],out[M],cnt=0;
void dfs(int d,vector>&v,int pre)
{
int l=v.size();
in[d]=++cnt;
a[cnt]=v[i].second;
for(int i=0;il) add(a[--i]);
while(jr) del(a[j--]);
return res;
}
signed main()
{
cin>>n>>m>>k;
v=sqrt(n*1.0);
for(int a,b,c,i=1;i
说过子树一定用dfs序,过程中还是想偏了
思路:简单模拟
题意看懂问题就不大,大概是每回合两笔收入,一个是5,一个是n/10,而后者最多是5。用循环实现即可
#include
#include
using namespace std;
#define fo(a,b) for(int i=a;i<=b;i++)
#define inf 0x3f3f3f3f
#define dou double
#define EXP 1e-8
#define ll long long
#define M 1000005
int t;
ll n,m,sum=0;
ll a[M];
int main()
{
cin>>n>>m;
while(m--){
n+=(5+min((ll)5,n/10));
}
cout<
这题是最亏的,大概率用到极角排序求凸包,最后求凸包面积吧,但是思路只有时间复杂度为2^50的暴力搜索,可能再加点凸包封闭不再搜索的优化,太麻烦了码一半自己放弃了。
但是看完唯一的视频题解,样例怎么都没法过,大概思路就是贡献思维,一个边能被贡献上只有右边没有一个点可以理解,但是边贡献的面积是什么都没听懂。
枚举三角形要么多情况,要么少情况,以后有机会会了再更吧
思路:思维+sort
首先字符后面.mp4其实是不影响顺序的,就是数字的字典序排序,n如果很大的话,比如n为100100。可以发现,前面的都是1,10,100,1000,....,100000,100001,100002,100003.....
也就是从s=1开始,每*10添加往后50个数字,s+0,s+1,s+2...s+50,将这些不多的字符串进行sort排序输出即可,也就是保证答案被收录,剩下的交给sort。
这是比赛时保证不WA的代码,再精简情况也是完全可以的
int s=1;
while(s
总代码:
#include
using namespace std;
#define fo(a,b) for(int i=a;i<=b;i++)
#define inf 0x3f3f3f3f
#define ll long long
#define M 100005
int n,l=0;
string s[M];
void add(int d)
{
l++;
while(d){
s[l]+='0'+d%10;
d/=10;
}
reverse(s[l].begin(),s[l].end());
s[l]+=".mp4";
}
int main()
{
cin>>n;
if(n<10000){
fo(1,n){
add(i);
}
}
else{
int s=1;
while(s
思路:线性基
这题属实离谱,要是只选两个的话,妥妥的字典树
然而这是线性基的模板题,那就没什么好说的了,下面是网上搜的最短的代码,还是自己学一下这个算法比较好
总代码:
#include
using namespace std;
typedef long long ll;
const int N=50+5,Maxbit=50;
ll p[N+1];
int main(){
int n;scanf("%d",&n);
for(int i=1;i<=n;++i){
ll x;scanf("%lld",&x);
for(int j=Maxbit;j>=0;--j){
if(!((x>>j)&1)) continue;
if(!p[j]) {p[j]=x;break;}
x^=p[j];
}
}
ll ans=0,t;
for(int j=Maxbit;j>=0;--j){
t=ans^p[j];
if(t>ans) ans=t;
}
printf("%lld\n",ans);
}
思路:简单模拟
思路就是求最大值,sort或者挨个比较都行,签到题
总代码:
#include
#include
using namespace std;
#define fo(a,b) for(int i=a;i<=b;i++)
#define inf 0x3f3f3f3f
#define dou double
#define EXP 1e-8
#define ll long long
#define M 1000005
int t;
int n;
int a[M];
int main()
{
cin>>n;
fo(1,n){
cin>>a[i];
}
sort(a+1,a+n+1);
cout<
思路:思维
这题代码不需要线段树的,但是不会线段树题意是很难懂的,要明白任何时候这个满线段树都是合法的线段树,即顶点=两个子点的和,加子点多少,顶点也加多少,但顶点仍是两子点和
那么所有子点往上走,路程和,也就是答案 =(所有子点和)*(2 ^ 层数-1)
这个图的答案就是
1+3+10 + 2+3+10 + 3+7+10 + 4+7+10
1+2+3+4 就是所有子点和=10,(3+7)+(3+7)=所有子点和*2,10+10+10+10=所有子点和*4。
最后就是(所有子点和)*(1+2+4)=(所有子点和)*(2 ^ 层数-1)
层数是不变的,(2 ^ 层数-1)就= 2*n-1
所以只求所有子点和,那就很简单了,累加ans,每次变化 ans+=z*(y-x+1);
scanf("%lld%lld%lld",&x,&y,&z);
ans+=z*(y-x+1);
总代码:
#include
using namespace std;
#define ll long long
#define M 1000005
#define lowbit(a) ((a)&(-a))
#define ll long long
ll n,m,a;
ll ans=0;
int main()
{
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++){
scanf("%lld",&a);
ans+=a;
}
for(int i=1;i<=m;i++)
{
ll x,y,z;
scanf("%lld%lld%lld",&x,&y,&z);
ans+=z*(y-x+1);
printf("%lld\n",ans*(n*2-1));
}
return 0;
}
可以发现前面的是思维,这个是比较接近正式赛的。后面的算法题就很多了,大多是偏算法模板题的。