51nod算法马拉松15

智力彻底没有了。。。看来再也拿不到奖金了QAQ。。。

A B君的游戏

因为数据是9B1L,所以我们可以hash试一下数据。。。

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
using namespace std;
inline int read() {
    int x=0,f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c==‘-‘) f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-‘0‘;
    return x*f;
}
typedef unsigned long long ll;
int main() {
	int n=read();ll ans=0,ans2=0;
	rep(i,1,n) {
		ll c;scanf("%llu",&c);
		ans^=c;ans2^=(c%52501);
	}
	if((ans&1)&&(!(ans&2))&&(ans&4)&&(ans2&1)&&(!(ans2&2))) puts("L");
	else puts("B");
	return 0;
}

B 完美消除

这道数位DP题应该还是不错的,我们先考虑给定一个数消成0的最小步数如何计算。

从高位到低位依次考虑每一位,设当前数字为x,将栈里所有大于x的数字删除,如果此时栈里没有数字x则加入,并且答案+1。

我们把这个想法套到数位DP中,设f[len][S][k][c]表示前len位,栈中集合为S,当前已经进行过k次操作,当前的数与给定数的大小关系。

转移时枚举下一位填什么数字即可。

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
using namespace std;
inline int read() {
    int x=0,f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c==‘-‘) f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-‘0‘;
    return x*f;
}
typedef long long ll;
int k,bit[20];
ll f[20][1050][20][2];
//f[len][S][sumv][<?=]
ll solve(ll n) {
	memset(f,0,sizeof(f));
	int len=0;
	while(n) bit[++len]=n%10,n/=10;
	reverse(bit+1,bit+len+1);
	f[0][1][0][0]=1;
	rep(i,1,len) rep(S,1,1023) rep(v,0,k) rep(c,0,1) {
		ll ans=f[i-1][S][v][c];if(!ans) continue;
		rep(y,0,9) if(y<=bit[i]||c) {
			int S2=S|(1<<y),k2=v+1;
			rep(j,y+1,9) if(S>>j&1) S2^=(1<<j);
			if(S>>y&1) k2--;
			f[i][S2][k2][c|(y<bit[i])]+=ans;
		}
	}
	ll ans=0;
	rep(S,1,1023) ans+=f[len][S][k][1];
	return ans;
}
int main() {
	ll l,r;scanf("%lld%lld",&l,&r);k=read();
	printf("%lld\n",solve(r+1)-solve(l));
	return 0;
}

C lyk与gcd

枚举(i,j)= k,考虑维护S[k]=sigma{A[i]  |  k|i},然后再容斥一下就能计算出每次询问的答案了。

所以我们预处理出来所有数的因数和mu函数,然后就能每次O(sqrt(N))实现了。

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
using namespace std;
inline int read() {
    int x=0,f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c==‘-‘) f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-‘0‘;
    return x*f;
}
const int maxn=100010;
const int maxm=2000010;
typedef long long ll;
int first[maxn],next[maxm],to[maxm],cnt,e;
void Addpri(int u,int v) {to[++e]=v;next[e]=first[u];first[u]=e;}
int vis[maxn],mu[maxn],pri[maxn];
void init(int n) {
	rep(i,1,n) for(int j=i;j<=n;j+=i) Addpri(j,i);
	mu[1]=1;
	rep(i,2,n) {
		if(!vis[i]) pri[++cnt]=i,mu[i]=-1;
		rep(j,1,cnt) {
			if(pri[j]*i>n) break;
			vis[pri[j]*i]=1;
			if(i%pri[j]==0) {mu[i*pri[j]]=0;continue;}
			mu[i*pri[j]]=-mu[i];
		}
	}
}
int B[maxn],sum;
int n,m,A[maxn];
void Add(int x,int v) {
	sum+=v;
	for(int i=first[x];i;i=next[i]) B[to[i]]+=v*mu[to[i]];
}
int query(int x) {
	int res=0;
	for(int i=first[x];i;i=next[i]) res+=B[to[i]];
	return res;
}
int main() {
	n=read();m=read();init(n);
	rep(i,1,n) Add(i,A[i]=read());
	rep(i,1,m) {
		int t=read(),x=read();
		if(t==2) printf("%d\n",query(x));
		else {
			int v=read();Add(x,v-A[x]);
			A[x]=v;
		}
	}
	return 0;
}

E Danganronpa

我的做法是基于AC自动机的。

考虑先将证言串和言弹串放在一棵AC自动机上,则一个言弹对一个证言的伤害即为证言有多少前缀在言弹对应fail树的子树。

考虑对每个询问以证言出现时间为第一关键字、以询问时间为第二关键字、AC自动机上位置为第三关键字,然后直接跑树上莫队即可。

时间复杂度为O(N^(5/3)logN)。但因为常数较小所以还可以跑过。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
using namespace std;
inline int read() {
    int x=0,f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c==‘-‘) f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-‘0‘;
    return x*f;
}
typedef long long ll;
const int maxn=200010;
int SIZE,ch[maxn][26],pa[maxn],cnt;
int insert(int p,int c) {
	if(!ch[p][c]) ch[p][c]=++cnt;
	pa[ch[p][c]]=p;
	return ch[p][c];
}
int f[maxn],que[maxn],first1[maxn],first2[maxn],e1,e2;
struct Edge {
	int to,next;
}edges1[maxn],edges2[maxn];
void AddEdge1(int u,int v) {edges1[++e1]=(Edge){v,first1[u]};first1[u]=e1;}
void AddEdge2(int u,int v) {edges2[++e2]=(Edge){v,first2[u]};first2[u]=e2;}
int dep[maxn],sta[maxn],cur[maxn],blo[maxn],top,tmp;
void dfs1(int x) {
	dep[x]=dep[pa[x]]+1;cur[x]=top;
	for(int i=first1[x];i;i=edges1[i].next) {
		int v=edges1[i].to;dfs1(v);
		if(top-cur[x]>SIZE) {
			tmp++;
			while(top>cur[x]) blo[sta[top--]]=tmp;
		}
	}
	sta[++top]=x;
}
int st[maxn],en[maxn];
void dfs2(int x) {
	st[x]=++tmp;
	for(int i=first2[x];i;i=edges2[i].next) dfs2(edges2[i].to);
	en[x]=tmp;
}
void getfail() {
	int l=1,r=0;
	rep(c,0,25) if(ch[0][c]) que[++r]=ch[0][c];
	while(l<=r) {
		int x=que[l++],v;
		rep(c,0,25) if(v=ch[x][c]) {
			que[++r]=v;int j=f[x];
			while(j&&!ch[j][c]) j=f[j];
			f[v]=ch[j][c];
		}
	}
	rep(i,1,cnt) AddEdge1(pa[i],i);
	dfs1(0);while(top) blo[sta[top--]]=tmp;
	rep(i,1,cnt) AddEdge2(f[i],i);
	tmp=0;dfs2(0);
}
int posa[maxn],tima[maxn],posb[maxn],ca,cb;
int n,m,q,t[maxn],p[maxn],blt[maxn];
struct Query {
	int b,t,x;
	bool operator < (const Query& ths) const {
		if(blo[x]!=blo[ths.x]) return blo[x]<blo[ths.x];
		if(blt[t]!=blt[ths.t]) return t<ths.t;
		return b<ths.b;
	}
}Q[maxn];
struct Fenwich {
	int sumv[maxn];
	Fenwich() {memset(sumv,0,sizeof(sumv));}
	void add(int x,int v) {for(;x<=cnt+1;x+=x&-x) sumv[x]+=v;}
	int sum(int x) {int res=0;for(;x;x-=x&-x) res+=sumv[x];return res;}
}T1,T2;
ll curans,ans[maxn];
int lca(int u,int v) {
	while(u!=v) {
		if(dep[u]<dep[v]) swap(u,v);
		u=pa[u];
	}
	return v;
}
void Move(int u,int v) {
	int c=lca(u,v);
	while(u!=c) {
		curans-=T1.sum(st[u]);
		T2.add(st[u],-1);
		u=pa[u];
	}
	while(v!=c) {
		curans+=T1.sum(st[v]);
		T2.add(st[v],1);
		v=pa[v];
	}
}
void U(int x,int v) {
	if(!x) return;
	T1.add(st[x],v);T1.add(en[x]+1,-v);
	curans+=(T2.sum(en[x])-T2.sum(st[x]-1))*v;
}
int main() {
	n=read();SIZE=sqrt(n*15);
	rep(i,1,n) blt[i]=(i-1)/SIZE+1;
	rep(i,1,n) {
		ans[i]=-1;
		char cmd[20],c[2];int x;
		scanf("%s",cmd);
		if(cmd[0]==‘I‘) {
			scanf("%s%d",c,&x);
			posa[++ca]=insert(posa[x],c[0]-‘a‘);
		}
		if(cmd[0]==‘A‘) {
			scanf("%s%d",c,&x);
			posb[++cb]=insert(posb[x],c[0]-‘a‘);
			tima[cb]=i;
		}
		if(cmd[0]==‘S‘) t[++q]=i,p[q]=posa[read()];
		if(cmd[0]==‘Q‘) x=read(),Q[++m]=(Query){tima[x],i,posb[x]};
	}
	getfail();
	int cx=0,l=1,r=0;
	sort(Q+1,Q+m+1);
	rep(i,1,m) {
		if(!Q[i].b) {ans[Q[i].t]=0;continue;}
		while(t[l]<Q[i].b) U(p[l++],-1);
		while(l&&t[l-1]>Q[i].b) U(p[--l],1);
		while(r<q&&t[r+1]<Q[i].t) U(p[++r],1);
		while(t[r]>Q[i].t) U(p[r--],-1);
		Move(cx,Q[i].x);cx=Q[i].x;
		ans[Q[i].t]=curans;
	}
	rep(i,1,n) if(ans[i]>=0) printf("%lld\n",ans[i]);
	return 0;
}

  

时间: 2024-08-29 03:47:57

51nod算法马拉松15的相关文章

51Nod 算法马拉松15 记一次悲壮而又开心的骗分比赛

OwO 故事的起源大概是zcg前天发现51Nod晚上有场马拉松,然后他就很开心的过去打了 神奇的故事就开始了: 晚上的时候我当时貌似正在写线段树?然后看见zcg一脸激动告诉我第一题有九个点直接输出B就可以A.. 然后之后zcg以奇怪的二分方式发现了如何A掉第一题的第十个点(我记得貌似是什么第5000个数等于511? OwO 就这样没有任何思考含量全凭骗分黑科技过掉了第一题 OwO 然后zcg打开了第二题,发现第二题样例有点问题,然后就发了个帖子,直接去看第三题了 我去瞅了一眼,发现这不是gcd

51NOD 算法马拉松15(脱欧专场) B君的游戏(博弈)

传送门 B君的游戏 wwwwodddd (命题人) 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 B君和L君要玩一个游戏.刚开始有n个正整数 ai . 双方轮流操作.每次操作,选一个正整数x,将其移除,再添加7个数字 x1,x2-x7 .要求对于 xi ,满足 0<= xi < x 且 x&xi=xi 注意0不能被选取,所以这个游戏一定会结束,而谁无法操作谁就失败. B君根据自己的经验,认为先手胜率高一点,所以B君是先手. B君想知道自己是否必胜. Input 第一

51Nod 算法马拉松21(迎新年)

这次打算法马拉松是在星期五的晚上,发挥还算正常(废话,剩下的题都不会= =). 讲讲比赛经过吧. 8:00准时发题,拿到之后第一时间开始读. A配对,看上去像是二分图最大权匹配,一看范围吓傻了,先跳过读后面的题. B完全二叉树的方差,大概看了一遍,好神的样子,跳过. C多项式?好吧没学过FFT和NTT的我肯定不会,跳跳跳. D最大值,哎呦这函数什么破玩意儿,看不懂,跳跳跳. E B君的射击,卧槽毕克大人您出题就算了出这么一道码农题是要闹那样,跳跳跳. F那些年,我们一起讲的故事,卧槽这特么简直就

随便玩玩系列之一:SPOJ-RNG+51nod 算法马拉松17F+51nod 1034 骨牌覆盖v3

先说说前面的SPOJ-RNG吧,题意就是给n个数,x1,x2,...,xn 每次可以生成[-x1,x1]范围的浮点数,把n次这种操作生成的数之和加起来,为s,求s在[A,B]内的概率 连续形的概率,想象为一个n维长方体,有两个平面与这个几何图形相割,于是就变成了求面(体)积问题,一般要去重,n维区域系数:s^n/n!,至于区间问题,直接前缀之差搞定 然后就是悲催的算法马拉松17F题了...其实是道好题来的,只是出题人不知世界上还有这题,然后某大牛把思路理清后把答案直接搬了过来 经典的1*2骨牌覆

51nod算法马拉松 contest7

A题 链接:http://www.51nod.com/contest/problem.html#!problemId=1417 推荐链接:http://blog.csdn.net/a837199685/article/details/45009337 设美女取得正面概率是p,反面就是(1-p),就是美女取一正一反和一反一正的概率相同,然后推出公式y=((a+b)/2+b)/(2*(a+b)); 1 #include<iostream> 2 #include<cstdio> 3 #i

51Nod 算法马拉松23 开黑记

惨啊--虽然开了半天黑,但是还是被dalao们踩了-- 第二次开黑,还是被卡在rank20了,我好菜啊--= = 写一写比赛经过吧-- 看到题之后习惯性都打开,A~D看上去似乎并没有什么思路,F应该是道数论题,看了E感觉有点意思,一看数据范围,咦怎么只有$50000$,再仔细看一看式子,手动分情况讨论之后得到一个结论-- 这题是水的线段树维护莫队啊= = 然后就开始码码码,由于一些脑残错误调了一会儿,然后就得到了这样的结果: 我坚信自己莫队的复杂度没错,然后就开始各种王逸松卡常,使用的卡常技巧包

51nod 算法马拉松4

http://www.51nod.com/contest/problemList.html#!contestId=9 D 装盒子 拓扑排序?

51NOD算法马拉松 最大值问题 离线预处理+set lower_bound

题目:http://www.51nod.com/contest/problem.html#!problemId=1349 题意:100000个数的序列,有100000次询问,每次问区间最大值大于等于k的区间有多少? 思路:一开始没看到"大于等于",想了很久也不会,原来看错题了.看错题害死人. 一般询问的问题,如果不能用线段树log(n)求出,那么就离线做. 首先将询问按从大到小排序,再将序列中的每个数排序,注意记录序号. 对于当前询问,每加进一个数,我需要找到它在加进的序列(按大小有序

51nod 算法马拉松4 D装盒子(网络流 / 二分图最优匹配)

装盒子 基准时间限制:1 秒 空间限制:131072 KB 分值: 160 有n个长方形盒子,第i个长度为Li,宽度为Wi,我们需要把他们套放.注意一个盒子只可以套入长和宽分别不小于它的盒子,并且一个盒子里最多只能直接装入另外一个盒子 (但是可以不断嵌套),例如1 * 1 可以套入2 * 1,而2 * 1再套入2 * 2.套入之后盒子占地面积是最外面盒子的占地面积.给定N个盒子大小,求最终最小的总占地面积. Input 第一行一个数N表示盒子的个数. 接下来N行,每行两个正整数,表示每个盒子的长