博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
NOIP练习赛题目2
阅读量:4661 次
发布时间:2019-06-09

本文共 27310 字,大约阅读时间需要 91 分钟。

小K的农场
难度级别:C; 运行时间限制:1000ms; 运行空间限制:51200KB; 代码长度限制:2000000B
试题描述
小K在MC里面建立很多很多的农场,总共n个,以至于他自己都忘记了每个农场中种植作物的具体数量了,他只记得一些含糊的信息(共m个),以下列三种形式描述:农场a比农场b至少多种植了c个单位的作物,农场a比农场b至多多种植了c个单位的作物,农场a与农场b种植的作物数一样多。但是,由于小K的记忆有些偏差,所以他想要知道存不存在一种情况,使得农场的种植作物数量与他记忆中的所有信息吻合。
输入
第一行包括两个整数n和m,分别表示农场数目和小K记忆中的信息数目。
     接下来m行:
     如果每行的第一个数是1,接下来有3个整数a,b,c,表示农场a比农场b至少多种植了c个单位的作物。
     如果每行的第一个数是2,接下来有3个整数a,b,c,表示农场a比农场b至多多种植了c个单位的作物。
     如果每行第一个数是3,家下来有2个整数a,b,表示农场a终止的数量和b一样多。
输出
如果存在某种情况与小K的记忆吻合,输出“Yes”,否则输出“No”。
输入示例
3 3
3 1 2
1 1 3 1
2 2 3 2
输出示例
Yes
其他说明
三个农场种植数量可以为(2,2,1)。
对于100%的数据  1<=n,m,a,b,c<=10000.
 

小K的农场差分约束系统,用DFS的SPFA来判会快好多

#include
#include
#include
#include
#include
#include
#define rep(i,s,t) for(int i=s;i<=t;i++)#define dwn(i,s,t) for(int i=s;i>=t;i--)#define ren for(int i=first[x];i;i=next[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=10010;const int maxm=20010;struct SPFA { int n,m,first[maxn],next[maxm]; struct Edge { int from,to,dist;}edges[maxm]; void init(int n) { this->n=n;m=0; } void AddEdge(int u,int v,int w) { edges[++m]=(Edge){u,v,w};next[m]=first[u];first[u]=m; } int vis[maxn],d[maxn]; int dfs(int x) { if(vis[x]) return 1;vis[x]=1; ren { Edge& e=edges[i]; if(d[e.to]>d[x]+e.dist) { d[e.to]=d[x]+e.dist; if(dfs(e.to)) return 1; } } vis[x]=0;return 0; } int check() { rep(i,1,n) vis[i]=d[i]=0; rep(i,1,n) if(dfs(i)) return 1; return 0; }}sol;int main() { int n=read(),m=read();sol.init(n); rep(i,1,m) { int t=read(); if(t==3) { int x=read(),y=read(); sol.AddEdge(x,y,0);sol.AddEdge(y,x,0); } else if(t==1) { int x=read(),y=read(),v=read(); sol.AddEdge(x,y,-v); } else { int x=read(),y=read(),v=read(); sol.AddEdge(y,x,v); } } puts(sol.check()?"No":"Yes"); return 0;}/*3 23 1 21 1 2 1*/
View Code

 

czy的后宫3
难度级别:C; 运行时间限制:1000ms; 运行空间限制:51200KB; 代码长度限制:2000000B
试题描述

上次czy在机房妥善安排了他的后宫之后,他发现可以将他的妹子分为c种,他经常会考虑这样一个问题:在[l,r]的妹子中间,能挑选出多少不同类型的妹子呢?

注意:由于czy非常丧尸,所以他要求在所挑选的妹子类型在[l,r]中出现次数为正偶数,你懂得。

问题简述:n个数,m次询问,每次问[l,r]区间有多少个数恰好出现正偶数次

输入
第一行3个整数,表示n,c,m
第二行n个数,每个数Ai在[1,c]之间,表示一个Ai类型的妹子
接下来m行,每行两个整数l,r,表示询问[l,r]这个区间的答案
输出
有m行,表示第i次询问的答案
输入示例
5 5 3 
1 1 2 2 3
1 5
3 4
2 3
输出示例
2
1
0
其他说明
共有10组测试数据
1-4组n,m=500,2000,5000,10000,c=1000
5-7组n,m=20000,30000,40000,c=10000
8-10组n,m=50000,80000,100000,c=100000
数据保证随机生成

czy的后宫3离线莫队算法

#include
#include
#include
#include
#include
#include
#define rep(i,s,t) for(int i=s;i<=t;i++)#define dwn(i,s,t) for(int i=s;i>=t;i--)#define ren for(int i=first[x];i!=-1;i=next[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;int n,m,A[maxn],bl[maxn],ans[maxn];int nowans,num[maxn];struct Query { int l,r,id; bool operator < (const Query& ths) const { if(bl[l]!=bl[ths.l]) return bl[l]
Q[i].r) del(A[r--]); while(l>Q[i].l) add(A[--l]); while(r
View Code

 

czy的后宫4
难度级别:C; 运行时间限制:1000ms; 运行空间限制:51200KB; 代码长度限制:2000000B
试题描述

czy有很多妹子,妹子虽然数量很多,但是质量不容乐观,她们的美丽值全部为负数(喜闻乐见)。

czy每天都要带N个妹子到机房,她们都有一个独一无二的美丽值,美丽值为-1到-N之间的整数。他想要把这些妹子排成一个波动序列,这样相对“漂亮”(美丽值的绝对值较小)的妹子可以与她旁边的两个美丽值的绝对值较大的妹子形成鲜明的对比,整个序列相对将更加“美观”(不再那么无法直视)。

一个序列是波动序列仅当序列中的每个数比周围的两个数都大或都小(如果有的话)。

现在czy希望知道,长度为N的波动序列有多少种。两种序列A和B不同当且仅当存在一个i,使得Ai≠Bi。由于这个数目可能很大,你只对它除以P的余数感兴趣。
输入
输入文件czy.in仅含一行,两个正整数N, P。
输出
输出文件czy.out仅含一行,一个非负整数,表示你所求的答案对P取余之后的结果。
输入示例
4 7
输出示例
3
其他说明
对于20%的数据,满足N≤10;  
对于40%的数据,满足N≤18; 
对于70%的数据,满足N≤550;  
对于100%的数据,满足3≤N≤4200,P≤10^9。

czy的后宫4此题同“地精部落”

首先发现满足A1>A2和A1<A2且满足题意的序列一样多

设f[i][j]表示1到i的序列,A1在[1,j]范围且A1>A2的方案数

那么f[i][j]=f[i][j-1]+f[i-1][i-j]

前者是累加,后者表示满足A2<A3的序列,将所有数变为互补的n-Ai+1,那么A2应在[1,i-j]范围。

#include
#include
#include
#include
#include
#include
#define rep(i,s,t) for(int i=s;i<=t;i++)#define dwn(i,s,t) for(int i=s;i>=t;i--)#define ren for(int i=first[x];i!=-1;i=next[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;}int f[2][4500];int main() { int n=read(),p=read(); f[1][1]=1; rep(i,2,n) rep(j,1,n) { int x=i&1; f[x][j]=(f[x][j-1]+(i>=j?f[x^1][i-j]:0))%p; } printf("%d\n",n==1?1:f[n&1][n]*2%p); return 0;}
View Code

 

czy的后宫5
难度级别:C; 运行时间限制:1000ms; 运行空间限制:51200KB; 代码长度限制:2000000B
试题描述

czy要召集他的妹子,但是由于条件有限,可能每个妹子不能都去,但每个妹子都有一个美丽值,czy希望来的妹子们的美丽值总和最大(虽然……)。

czy有一个周密的电话通知网络,它其实就是一棵树,根结点为czy,他可以通知一些妹子(毕竟他不认识他的所有妹子嘛),称为他的下线(也就是儿子节点),下线们继续通知自己的下线。任何妹子都可以不去,但是任何一个妹子如果要去,则她的上线(也就是她的父亲节点)一定要去。

为了使妹子美丽值总和最大,czy想安排一下,(非强制)让一些妹子去。但是妹子数很多,人脑是难以应付的,所以他想让你用电脑解决。

输入
输入第一行两个整数n,m表示有n个妹子,至多只能去m个妹子。(1<=m<=n)
接下来2*n行,每两行代表一个妹子的信息(如果这个妹子没有子节点,就只有一行)。
每个妹子的第一行两个整数p,s,表示这个妹子美丽值为p,子节点个数s;(-100<=p<=100)
第二行s个整数,表示这个妹子的子节点的编号。czy的编号一定为1。
对于20%数据1<=n<=10
对于60%数据1<=n<=100
对于100%数据1<=n<=1000
输出
输出一个整数,表示权值的最大值。
输入示例
8 5
100 2
2 3
79 2
4 5
109 3
6 7 8
100 0
100 0
100 0
101 0
108 0
输出示例
518
 

czy的后宫5这题的做法很巧妙,先倒腾出DFS序,那么只有选根节点x才能选[L[x],R[x]]区间的节点。

那么可以做一个序列背包。设f[i][j]表示[i,n]的节点,f[i][j]=max(f[i+Size[q[i]]][j],f[i+1][j-1]+val[i])前者表示不选节点q[i],后者表示选

#include
#include
#include
#include
#include
#include
#define rep(i,s,t) for(int i=s;i<=t;i++)#define dwn(i,s,t) for(int i=s;i>=t;i--)#define ren for(int i=first[x];i;i=next[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=1010;int n,m,val[maxn],to[maxn],first[maxn],next[maxn],e;void AddEdge(int u,int v) { to[++e]=v;next[e]=first[u];first[u]=e;}int f[maxn][maxn],s[maxn],q[maxn],cnt;void dfs(int x) { q[++cnt]=x;s[x]=1; ren dfs(to[i]),s[x]+=s[to[i]];}int main() { n=read();m=read(); rep(i,1,n) { val[i]=read();int k=read(); while(k--) AddEdge(i,read()); } dfs(1); rep(i,1,n) f[i][1]=val[q[i]]; dwn(i,n-1,1) rep(j,1,m) f[i][j]=max(f[i+1][j-1]+val[q[i]],f[i+s[q[i]]][j]); int ans=-1<<30; rep(i,1,m) ans=max(ans,f[1][i]); printf("%d\n",ans); return 0;}
View Code

 

 

czy的后宫6
难度级别:C; 运行时间限制:1000ms; 运行空间限制:51200KB; 代码长度限制:2000000B
试题描述

众所周知的是丧尸czy有很多妹子(虽然很多但是质量不容乐观QAQ),今天czy把n个妹子排成一行来检阅。但是czy的妹子的质量实在……所以czy看不下去了。检阅了第i个妹子会增加czy a[i]的肾虚值,他打算在检阅过程中最多休息m次(一开始检阅算0次休息,就是说czy最多可以检阅m+1次),每次休息过后czy又会龙精虎猛的继续检阅。问怎样分配才能使得czy在检阅过程中的最大肾虚值最小。

       当然这么简单的问题czy早就会做啦……他原来还想算算满足肾虚值最小的条件下有几种方案,但是他太虚了,所以这个问题也交给你啦。你只要输出方案数mod 32123的值即可。

输入
第一行输入两个正整数n、m,表示czy的妹子数、最多的休息次数
接下来2到n+1行每行输入一个数a[i],意义见上
输出
第一行输出一个数s,表示最小的肾虚值
第二行输出一个数t,表示方案数
输入示例
4 2
3
4
5
2
输出示例
7
3
其他说明
有30%的数据,1<=n<=20
另30%的数据,1<=n<=200
另30%的数据,1<=n<=5000,1<=m<=min(n-1,1000),1<=a[i]<=1000
另10%的数据,1<=n<=20000,1<=m<=1000,a[i]只有1、2
保证80%数据随机生成,在计算过程中不会爆int

czy的后宫6前一问嘟嘟打工,后一问自己DP即可

#include
#include
#include
#include
#include
#include
#define rep(i,s,t) for(int i=s;i<=t;i++)#define dwn(i,s,t) for(int i=s;i>=t;i--)#define ren for(int i=first[x];i!=-1;i=next[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=20010;const int mod=32123;int n,m,A[maxn],S[maxn];int check(int mid) { int sum=0,cnt=0; rep(i,1,n) { if(sum+A[i]>mid) { sum=0; if(++cnt>=m) return 0; } sum+=A[i]; } return 1;}int f[2][maxn],g[2][maxn];int main() { int l=1,r=0,mid; n=read();m=read()+1; rep(i,1,n) A[i]=read(),r+=A[i],l=max(l,A[i]),S[i]=S[i-1]+A[i]; while(l
>1)) r=mid; else l=mid+1; printf("%d\n",l); f[0][0]=1;int cur=0,ans=0; rep(i,0,n) g[0][i]=1; rep(j,1,m) { cur^=1;int L=j-1; rep(i,j,n) { while(S[i]-S[L]>l) L++; f[cur][i]=(g[cur^1][i-1]-(L?g[cur^1][L-1]:0)+mod)%mod; g[cur][i]=(g[cur][i-1]+f[cur][i])%mod; } (ans+=f[cur][n])%=mod; } printf("%d\n",ans); return 0;}
View Code

 

 

蒟蒻czy又被D飞了
难度级别:C; 运行时间限制:1000ms; 运行空间限制:51200KB; 代码长度限制:2000000B
试题描述
机房里的各路巨神天天D蒟蒻CZY,早已是他们的日常任务了。(今天的机房也是很和平呢)

这一次他们安排好了一种方式来D蒟蒻Czy。每个人每次都能把Czy D飞一个高度(让Czy的高度+a[i]),由于他们的精♂力有限(尤其是某些后宫王),要保留体力应对接下来的战♂斗,所以他们每个人只会D Czy k[i]次。由于他们每个人的D人能力不同,各有所长,所以他们每个人都在Czy到一定高度h[i]以后良心发现,任由Czy自生自灭,回去玩达尔文进化岛了。

所以Czy想知道他的速度是否能达到第二宇宙速度,离开这个可怕的地方。但是Czy太弱了,所以这个问题就交给了未来集训队的你。但是你这么吊,哪里屑解答Czy蒟蒻的问题。于是你打算只告诉他最高会飞到什么高度,让他自己算自己的速度去。

输入
第1行:1个整数N(1<=N<=100)N表示机房里有多少人今天要D 蒟蒻Czy
     接下里N行,每行描述一个神犇的信息  a[i] h[i] k[i]
输出
第1行:1个整数H,表示Czy最高会被神犇们D到哪里去
输入示例
7
8 35 1
5 35 1
15 35 1
8 35 1
10 35 1
4 35 1
2 35 1
输出示例
35
其他说明
对于40%的数据  所有人的k[i]==1, n<=10,h[i]<=100 且所有人的h[i]相等 
对于100%的数据  1<=k[i]<=30,1<=h[i]<=10000,  1<=a[i]<=200 

蒟蒻czy又被D飞了直觉告诉我们,应该先让h[i]较小的人D,那么排序后做个背包

#include
#include
#include
#include
#include
#include
#include
#define rep(i,s,t) for(int i=s;i<=t;i++)#define dwn(i,s,t) for(int i=s;i>=t;i--)#define ren for(int i=first[x];i!=-1;i=next[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;}int f[10500];struct Orz { int a,h,k; bool operator < (const Orz& ths) const { return h
View Code

 

打地鼠游戏
难度级别:C; 运行时间限制:1000ms; 运行空间限制:51200KB; 代码长度限制:2000000B
试题描述

伟大的2320学长特别喜欢打地鼠游戏,这个游戏开始后,会在地板上冒出一些地鼠来,你可以用榔头去敲击这些地鼠,每个地鼠被敲击后,将会增加相应的游戏分值。可是,所有地鼠只会在地上出现一段时间(而且消失后再也不会出现),每个地鼠都在0时刻冒出,但停留的时间可能是不同的,而且每个地鼠被敲击后增加的游戏分值也可能是不同。

最近2320学长经常玩这个游戏,以至于敲击每个地鼠只要1秒。他在想如何敲击能使总分最大。
输入
输入包含3行,第一行包含一个整数n(1<=n<=100000)表示有n个地鼠从地上冒出来,第二行n个用空格分隔的整数表示每个地鼠冒出后停留的时间(Maxt<=50000),第三行n个用空格分隔的整数表示每个地鼠被敲击后会增加的分值v(v<=1000)。每行中第i个数都表示第i个地鼠的信息。
输出
无。
输入示例
5
5 3 6 1 4
7 9 2 1 5
输出示例
24
其他说明
30%的数据保证n<=100, t<=500,v<=50
60%的数据保证 n<=10000,t<=3000,v<=500
100%的数据保证 n<=100000,t<=5000,v<=1000

打地鼠游戏先按时间排序,将已选择的项目扔到一个堆里,每次如果发现不能满足需求,将堆中收益最少的扔出来。

#include
#include
#include
#include
#include
#include
#define rep(i,s,t) for(int i=s;i<=t;i++)#define dwn(i,s,t) for(int i=s;i>=t;i--)#define ren for(int i=first[x];i!=-1;i=next[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;}priority_queue
Q;const int maxn=100010;struct Rat { int t,x; bool operator < (const Rat& ths) const { return t
A[i].t) { ans+=Q.top(); Q.pop(); SIZE--; } } printf("%d\n",ans); return 0;}
View Code

 

果实计数
难度级别:C; 运行时间限制:1000ms; 运行空间限制:51200KB; 代码长度限制:2000000B
试题描述

淘淘家有棵奇怪的苹果树,这棵树共有n+1层,标号为0~n。这棵树第0层只有一个节点,为根节点。已知这棵树为b叉树,且保证是一颗满b叉树。如图为一颗满3叉树。

现在,该树第n层的每个节点上都结出了一个苹果,淘淘想知道共结了多少苹果。由于数量可能很大,答案要求输出mod k后的结果。

输入
给出第1层的节点数b和层数n和k
输出
输出苹果数mod k后的结果。
输入示例
2 10 9
输出示例
7
其他说明
30%的数据保证:b<=100,n<=10, k<=100.
100%的数据保证:b<2^31,n<2^31,k<=2^15

果实计数。。。练练矩阵快速幂么

#include
#include
#include
#include
#include
#include
#define rep(i,s,t) for(int i=s;i<=t;i++)#define dwn(i,s,t) for(int i=s;i>=t;i--)#define ren for(int i=first[x];i!=-1;i=next[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 n,b,MOD;struct Matrix { ll A[3][3]; Matrix() {memset(A,0,sizeof(A));} Matrix operator * (const Matrix& b) const { Matrix c; rep(i,0,2) rep(j,0,2) { c.A[i][j]=0; rep(k,0,2) c.A[i][j]+=A[i][k]*b.A[k][j]; c.A[i][j]%=MOD; } return c; } void print() { rep(i,0,2) { rep(j,0,2) printf("%lld ",A[i][j]); puts(""); } }};void pow(Matrix& ans,int n) { Matrix t=ans;n--; while(n) { if(n&1) ans=ans*t; t=t*t;n>>=1; }}int main() { b=read(),n=read(),MOD=read(); Matrix ans; ans.A[0][0]=b;ans.A[1][0]=b;ans.A[1][1]=1;ans.A[2][2]=1; pow(ans,n);printf("%lld\n",ans.A[0][0]); return 0;}
View Code

 

皇帝的烦恼
难度级别:C; 运行时间限制:1000ms; 运行空间限制:262144KB; 代码长度限制:2000000B
试题描述

经过多年的杀戮,秦皇终于统一了中国。为了抵御外来的侵略,他准备在国土边境安置n名将军。不幸的是这n名将军羽翼渐丰,开始展露他们的狼子野心了。他们拒绝述职、拒绝接受皇帝的圣旨。秦皇已经准备好了秘密处决这些无礼的边防大将。不过为防兵变,他决定先授予这些将军一些勋章,为自己赢得战略时间。将军们听说他们即将被授予勋章都很开心,他们纷纷上书表示感谢。第i个将军要求得到ai枚不同颜色的勋章。但是这些将军都很傲气,如果两个相邻的将军拥有颜色相同的勋章他们就会认为皇帝不尊重他们,会立即造反(编号为i的将军和编号为i+1的将军相邻;因为他们驻扎的边境可以类似看成一个圆形,所以编号1和编号n的将军也相邻)。皇帝不得不满足每个将军的要求,但对他们的飞扬跋扈感到很气愤。于是皇帝决定铸造尽量少种类的勋章来满足这些狂妄者的要求。请问他至少要铸造多少种颜色的勋章?

 第一行有一个整数n(1<=n<=20000)。接下来n行每行一个整数ai,表示第i个将军要求得到多少种勋章。(1<=ai<=100000) 输出一个整数,即最少需要多少种勋章。

输入
输出
输入示例
4
2 2 1 1
输出示例
4
其他说明
1<=n<=20000
1<=ai<=100000

皇帝的烦恼去看训练指南吧

#include
#include
#include
#include
#include
#include
#define rep(i,s,t) for(int i=s;i<=t;i++)#define dwn(i,s,t) for(int i=s;i>=t;i--)#define ren for(int i=first[x];i!=-1;i=next[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=20010;int n,A[maxn],Left[maxn],Right[maxn];int check(int mid) { int x=A[1],y=mid-A[1]; Left[1]=x;Right[1]=0; rep(i,2,n) if(i&1) Right[i]=min(y-Right[i-1],A[i]),Left[i]=A[i]-Right[i]; else Left[i]=min(x-Left[i-1],A[i]),Right[i]=A[i]-Left[i]; return !Left[n];}int main() { n=read(); rep(i,1,n) A[i]=read(); if(n==1) {printf("%d\n",A[1]);return 0;} A[n+1]=A[1]; int L=0,R=0,mid; rep(i,1,n) L=max(L,A[i]+A[i+1]); if(n&1) { rep(i,1,n) R=max(R,A[i]*3); while(L
>1)) R=mid; else L=mid+1; } printf("%d\n",L); return 0;}
View Code

 

梦幻布丁
难度级别:C; 运行时间限制:1000ms; 运行空间限制:262144KB; 代码长度限制:2000000B
试题描述
N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为1,2,2,1的四个布丁一共有3段颜色
输入
第一行给出N,M表示布丁的个数和好友的操作次数. 第二行N个数A1,A2...An表示第i个布丁的颜色从第三行起有M行,对于每个操作,若第一个数字是1表示要对颜色进行改变,其后的两个整数X,Y表示将所有颜色为X的变为Y,X可能等于Y. 若第一个数字为2表示要进行询问当前有多少段颜色,这时你应该输出一个整数.
输出
针对第二类操作即询问,依次输出当前有多少段颜色.
输入示例
4 3
1 2 2 1
2
1 2 1
2
输出示例
3
1
其他说明
n,m<=100000 x,y<=1000000

梦幻布丁启发式合并。每次将少的颜色改成多的颜色,同时要记一下每个颜色究竟是那种颜色。

#include
#include
#include
#include
#include
#include
#define rep(i,s,t) for(int i=s;i<=t;i++)#define dwn(i,s,t) for(int i=s;i>=t;i--)#define ren for(int i=first[x];i!=-1;i=next[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=1000010;int s[maxn],first[maxn],next[maxn],last[maxn],ToT;void AddPos(int x,int v) { if(!first[x]) last[x]=v; s[x]++;next[++ToT]=first[x];first[x]=ToT;}int n,m,ans,A[100010],pa[maxn];void merge(int x,int y) { for(int i=first[x];i;i=next[i]) { if(y==A[i-1]) ans--; if(y==A[i+1]) ans--; } for(int i=first[x];i;i=next[i]) A[i]=y; next[last[x]]=first[y];first[y]=first[x];s[y]+=s[x]; s[x]=0;}int main() { n=read();int q=read(); rep(i,1,n) A[i]=read(),m=max(m,A[i]),AddPos(A[i],i); rep(i,1,n) ans+=A[i]!=A[i-1]; rep(i,1,m) pa[i]=i; while(q--) { if(read()==1) { int x=read(),y=read();if(x==y) continue; if(s[pa[x]]>s[pa[y]]) swap(pa[x],pa[y]); x=pa[x];y=pa[y]; if(!s[x]) continue; merge(x,y); } else printf("%d\n",ans); } return 0;}
View Code

 

黑魔法师之门
难度级别:C; 运行时间限制:1000ms; 运行空间限制:51200KB; 代码长度限制:2000000B
试题描述
经过了16 个工作日的紧张忙碌,未来的人类终于收集到了足够的能源。然而在与Violet星球的战争中,由于Z 副官的愚蠢,地球的领袖applepi 被邪恶的黑魔法师Vani 囚禁在了Violet 星球。为了重启Nescafé这一宏伟的科技工程,人类派出了一支由XLk、Poet_shy 和lydrainbowcat 三人组成的精英队伍,穿越时空隧道,去往Violet 星球拯救领袖applepi。applepi 被囚禁的地点只有一扇门,当地人称它为“黑魔法师之门”。这扇门上画着一张无向无权图,而打开这扇门的密就是图中每个点的度数大于零且都是偶数的子图的个数对1000000009 取模的值。此处子图 (V, E) 定义为:点集V 和边集E 都是原图的任意子集,其中E 中的边的端点都在V 中。但是Vani 认为这样的密码过于简单,因此门上的图是动态的。起初图中只有N 个顶点而没有边。Vani 建造的门控系统共操作M 次,每次往图中添加一条边。你必须在每次操作
后都填写正确的密码,才能够打开黑魔法师的牢狱,去拯救伟大的领袖applepi。
输入
第一行包含两个整数N 和M。
接下来M 行,每行两个整数A 和B,代表门控系统添加了一条无向边 (A, B)。
输出
输出一共M 行,表示每次操作后的密码。
输入示例
4 8
3 1
3 2
2 1
2 1
1 3
1 4
2 4
2 3
输出示例
0
0
1
3
7
7
15
31
其他说明
对于30%的数据, N, M≤10 。
对于100%的数据, N≤200000 ,M≤300000 。

黑魔法师之门应该看看样例就能发现结论了。

证明?我好像也不太懂。。。

#include
#include
#include
#include
#include
#include
#define rep(i,s,t) for(int i=s;i<=t;i++)#define dwn(i,s,t) for(int i=s;i>=t;i--)#define ren for(int i=first[x];i!=-1;i=next[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=200010;const int mod=1000000009;int pa[maxn],ans;int findset(int x) { return x==pa[x]?x:pa[x]=findset(pa[x]);}int main() { int n=read(),m=read(); rep(i,1,n) pa[i]=i; while(m--) { int x=findset(read()),y=findset(read()); if(x!=y) pa[x]=y; else (ans=ans*2+1)%=mod; printf("%d\n",ans); } return 0;}
View Code

 

守卫者的挑战
难度级别:C; 运行时间限制:1000ms; 运行空间限制:262144KB; 代码长度限制:2000000B
试题描述
打开了黑魔法师Vani的大门,队员们在迷宫般的路上漫无目的地搜寻着关押applepi的监狱的所在地。突然,眼前一道亮光闪过。“我,Nizem,是黑魔法圣殿的守卫者。如果你能通过我的挑战,那么你可以带走黑魔法圣殿的地图……”瞬间,队员们被传送到了一个擂台上,最初身边有一个容量为K的包包。
擂台赛一共有N项挑战,各项挑战依次进行。第i项挑战有一个属性ai,如果ai>=0,表示这次挑战成功后可以再获得一个容量为ai的包包;如果ai=-1,则表示这次挑战成功后可以得到一个大小为1 的地图残片。地图残片必须装在包包里才能带出擂台,包包没有必要全部装满,但是队员们必须把 【获得的所有的】地图残片都带走(没有得到的不用考虑,只需要完成所有N项挑战后背包容量足够容纳地图残片即可),才能拼出完整的地图。并且他们至少要挑战成功L次才能离开擂台。
队员们一筹莫展之时,善良的守卫者Nizem帮忙预估出了每项挑战成功的概率,其中第i项挑战成功的概率为pi%。现在,请你帮忙预测一下,队员们能够带上他们获得的地图残片离开擂台的概率。
输入
第一行三个整数N , L , K 。
第二行N 个实数,第i 个实数i p 表示第i 项挑战成功的百分比。
第三行N 个整数,第i 个整数i a 表示第i 项挑战的属性值.
输出
一个整数,表示所求概率,四舍五入保留6 位小数。
输入示例
3 1 0
10 20 30
-1 -1 2
输出示例
0.300000
其他说明
对于 100% 的数据,保证0<=K<=2000,0<=N<=200,-1<=ai<=1000,0<=L<=N,0<=pi<=100.

守卫者的挑战将一个碎片转化成一个容量为-1的包,然后按大到小排序后DP。

#include
#include
#include
#include
#include
#include
#define rep(i,s,t) for(int i=s;i<=t;i++)#define dwn(i,s,t) for(int i=s;i>=t;i--)#define ren for(int i=first[x];i!=-1;i=next[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=210;double f[maxn][maxn][maxn];struct P { double p;int a; bool operator < (const P& ths) const { return a>ths.a;}}A[maxn];int main() { int n=read(),l=read(),k=min(read(),n); rep(i,1,n) scanf("%lf",&A[i].p),A[i].p/=100.0; rep(i,1,n) A[i].a=read(); sort(A+1,A+n+1); f[0][0][k]=1.0; rep(i,1,n) rep(j,0,n) rep(w,0,n) { if(w+A[i].a>=0) f[i][j+1][min(w+A[i].a,n)]+=f[i-1][j][w]*A[i].p; f[i][j][w]+=f[i-1][j][w]*(1.0-A[i].p); } double ans=0.0; rep(j,l,n) rep(w,0,n) ans+=f[n][j][w]; printf("%.6lf\n",ans); return 0;}
View Code

 

穿越七色虹
难度级别:C; 运行时间限制:1000ms; 运行空间限制:51200KB; 代码长度限制:2000000B
试题描述

输入
第一行两个实数 h、x0,表示身高和目的地横坐标。 接下来七行每行两个实数 xi、ri,表示七座半圆形彩虹的圆心和半径。
输出格式
输出最小的 r,四舍五入保留 2 位小数。
输出
输入示例
4.0 36.0
0.0 4.0
6.0 4.0
12.0 4.0
18.0 4.0
24.0 4.0
30.0 4.0
36.0 4.0
输出示例
1.00
其他说明
对于 100% 的数据,满足 0<=xi,x0<=10000,0<h<100。
 

穿越七色虹二分答案,判定时直接判断最上方的一条线段有没有被覆盖。

#include
#include
#include
#include
#include
#include
#define rep(i,s,t) for(int i=s;i<=t;i++)#define dwn(i,s,t) for(int i=s;i>=t;i--)#define ren for(int i=first[x];i!=-1;i=next[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=8;const double eps=1e-4;int n=7;double x[maxn],r[maxn],h,x0;struct Line { double L,R; bool operator < (const Line& ths) const { return L
eps||0.0-A[i].R>eps) continue; if(A[i].L-mx>eps) ok=0; mx=max(mx,A[i].R); } if(x0-mx>eps) ok=0; rep(i,1,n) r[i]-=delta; return ok;}int main() { scanf("%lf%lf",&h,&x0); rep(i,1,n) scanf("%lf%lf",&x[i],&r[i]); double l=0.0,r=1000000.0; while(r-l>eps) { double mid=(l+r)*0.5; if(check(mid)) r=mid; else l=mid; } printf("%.2lf\n",l); return 0;}
View Code
还教室
难度级别:C; 运行时间限制:1000ms; 运行空间限制:262144KB; 代码长度限制:2000000B
试题描述

输入
同上
输出
同上
输入示例
同上
输出示例
同上
其他说明
1<=n,m<=100000

还教室线段树ing

#include
#include
#include
#include
#include
#include
#define rep(i,s,t) for(int i=s;i<=t;i++)#define dwn(i,s,t) for(int i=s;i>=t;i--)#define ren for(int i=first[x];i!=-1;i=next[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;typedef long long ll;ll sumv[maxn*3],sumv2[maxn*3],addv[maxn*3];void pushdown(int o,int l,int r) { int lc=o<<1,rc=lc|1; if(addv[o]) { addv[lc]+=addv[o];addv[rc]+=addv[o]; addv[o]=0; }}void maintain(int o,int l,int r) { int lc=o<<1,rc=lc|1; if(l
>1,lc=o<<1,rc=lc|1; pushdown(o,l,r); if(ql<=mid) update(lc,l,mid,ql,qr,v); else maintain(lc,l,mid); if(qr>mid) update(rc,mid+1,r,ql,qr,v); else maintain(rc,mid+1,r); } maintain(o,l,r);}void build(int o,int l,int r) { if(l==r) addv[o]=read(); else { int mid=l+r>>1,lc=o<<1,rc=lc|1; build(lc,l,mid);build(rc,mid+1,r); } maintain(o,l,r);}ll ans1,ans2;void query(int o,int l,int r,int ql,int qr) { if(ql<=l&&r<=qr) ans1+=sumv[o],ans2+=sumv2[o]; else { int mid=l+r>>1,lc=o<<1,rc=lc|1; pushdown(o,l,r);maintain(lc,l,mid);maintain(rc,mid+1,r); if(ql<=mid) query(lc,l,mid,ql,qr); if(qr>mid) query(rc,mid+1,r,ql,qr); }}ll gcd(ll a,ll b) { return !b?a:gcd(b,a%b);}int main() { int n=read(),m=read(); build(1,1,n); while(m--) { int t=read(); if(t==1) { int l=read(),r=read(),v=read(); update(1,1,n,l,r,v); } else { int l=read(),r=read(); ans1=ans2=0;query(1,1,n,l,r); if(t==2) { ll x=ans1,y=r-l+1,c=gcd(x,y); printf("%lld/%lld\n",x/c,y/c); } else { ll x=ans2*(r-l+1)-ans1*ans1,y=(ll)(r-l+1)*(r-l+1),c=gcd(x,y); printf("%lld/%lld\n",x/c,y/c); } } } return 0;}
View Code

 

花园
难度级别:C; 运行时间限制:3000ms; 运行空间限制:262144KB; 代码长度限制:2000000B
试题描述
输入
对于每个询问操作,给出答案。
输出
输入示例
5 8 
10 20 30 40 50
1 2
1 3
3 4 
3 5 
Q 2 5 10 
C 2 21
Q 3 4 21 
C 6 22 
Q 1 7 28 
C 5 20
Q 2 5 20
Q 2 0 9 
输出示例
1
2
0
3

花园直接用DFS序即可,用动态开节点的线段树。

#include
#include
#include
#include
#include
#include
#define rep(i,s,t) for(int i=s;i<=t;i++)#define dwn(i,s,t) for(int i=s;i>=t;i--)#define ren for(int i=first[x];i;i=next[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=300010;const int hashsize=299673;const int maxnode=10000010;struct Hash_Map { int first[hashsize],next[maxn],val[maxn*2],ToT; int find(int v) { int p=v%hashsize;if(p<0) p+=hashsize; for(int i=first[p];i;i=next[i]) if(val[i]==v) return i; val[++ToT]=v;next[ToT]=first[p];return first[p]=ToT; }}M;int root[maxn],ls[maxnode],rs[maxnode],sumv[maxnode],addv[maxnode],ToT;void maintain(int o,int l,int r) { sumv[o]=sumv[ls[o]]+sumv[rs[o]]; sumv[o]+=addv[o]*(r-l+1);}void pushdown(int& o,int l,int r,int mid) { if(addv[o]) { if(!ls[o]) ls[o]=++ToT; if(!rs[o]) rs[o]=++ToT; addv[ls[o]]+=addv[o];addv[rs[o]]+=addv[o];addv[o]=0; maintain(ls[o],l,mid);maintain(rs[o],mid+1,r); }}void update(int& o,int l,int r,int ql,int qr,int v) { if(!o) o=++ToT; if(ql<=l&&r<=qr) addv[o]+=v; else { int mid=l+r>>1;pushdown(o,l,r,mid); if(ql<=mid) update(ls[o],l,mid,ql,qr,v); if(qr>mid) update(rs[o],mid+1,r,ql,qr,v); } maintain(o,l,r); //printf("%d %d %d %d\n",o,l,r,sumv[o]);}int query(int& o,int l,int r,int x) { if(!o||!x) return 0; if(l==r) return sumv[o]; else { int mid=l+r>>1;pushdown(o,l,r,mid); if(x<=mid) return query(ls[o],l,mid,x); return query(rs[o],mid+1,r,x); }}int n,q,first[maxn],next[maxn<<1],to[maxn<<1],e;int val[maxn];void AddEdge(int u,int v) { to[++e]=v;next[e]=first[u];first[u]=e; to[++e]=u;next[e]=first[v];first[v]=e;}int L[maxn],R[maxn],cnt,anc[maxn][20],dep[maxn];void dfs(int x,int fa) { anc[x][0]=fa;rep(i,1,19) anc[x][i]=anc[anc[x][i-1]][i-1]; L[x]=++cnt; dep[x]=dep[fa]+1; ren if(to[i]!=fa) { dfs(to[i],x); } R[x]=cnt;update(root[val[x]],1,n,L[x],R[x],1);}int LCA(int x,int y) { if(dep[x]
View Code

 

工资
难度级别:C; 运行时间限制:1000ms; 运行空间限制:51200KB; 代码长度限制:2000000B
试题描述

聪哥在暑假参加了打零工的活动,这个活动分为n个工作日,每个工作日的工资为Vi。有m个结算工钱的时间,聪哥可以自由安排这些时间,也就是说什么时候拿钱,老板说的不算,聪哥才有发言权!(因为聪哥是土豪,他是老板的老板)

聪哥不喜欢身上一次性有太多的钱,于是他想安排一下拿钱的时间,使他一次性拿的钱中最大的最小。(最后一天一定要领钱)

 

输入
第一行 2个数 n,m
接下来n行,每行一个数,代表Vi.
输出
最小的最大钱数。
输入示例
7 5
100
400
300
100
500
101
400
输出示例
500
其他说明
数据范围:
20%   1<=n<=20
另 20%  1<=n<=50,Vi的和不超过1000
100%  1<=n<=100,000,m<=n,Vi<=10,000
 

工资。。。这是第几次了?

#include
#include
#include
#include
#include
#include
#define rep(i,s,t) for(int i=s;i<=t;i++)#define dwn(i,s,t) for(int i=s;i>=t;i--)#define ren for(int i=first[x];i!=-1;i=next[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;int n,m,A[maxn];int check(int mid) { int sum=0,cnt=0; rep(i,1,n) { if(sum+A[i]>mid) { sum=0; if(++cnt>=m) return 0; } sum+=A[i]; } return 1;}int main() { int l=1,r=0,mid; n=read();m=read(); rep(i,1,n) A[i]=read(),r+=A[i],l=max(l,A[i]); while(l
>1)) r=mid; else l=mid+1; printf("%d\n",l); return 0;}
View Code

 

 

   
藏妹子之处(excel)
难度级别:C; 运行时间限制:1000ms; 运行空间限制:51200KB; 代码长度限制:2000000B
试题描述

今天CZY又找到了三个妹子,有着收藏爱好的他想要找三个地方将妹子们藏起来,将一片空地抽象成一个R行C列的表格,CZY要选出3个单元格。但要满足如下的两个条件:

(1)任意两个单元格都不在同一行。
(2)任意两个单元格都不在同一列。
选取格子存在一个花费,而这个花费是三个格子两两之间曼哈顿距离的和(如(x1,y1)和(x,y2)的曼哈顿距离为|x1-x2|+|y1-y2|)。狗狗想知道的是,花费在minT到maxT之间的方案数有多少。
答案模1000000007。所谓的两种不同方案是指:只要它选中的单元格有一个不同,就认为是不同的方案。

输入
 一行,4个整数,R、C、minT、maxT。3≤R,C≤4000, 1≤minT≤maxT≤20000。
对于30%的数据,  3 ≤ R, C ≤ 70。
输出
一个整数,表示不同的选择方案数量模1000000007后的结果。
输入示例
6 19 4 18776
输出示例
116280

发现三点的曼哈顿距离之和为其外包矩形的周长。

那么枚举外包矩形的长和宽,可以算出表格中有多少这样的矩形,再从矩形中选出三点即可。

#include
#include
#include
#include
#include
#include
#define rep(i,s,t) for(int i=s;i<=t;i++)#define dwn(i,s,t) for(int i=s;i>=t;i--)#define ren for(int i=first[x];i!=-1;i=next[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 mod=1000000007;ll cal(int r,int c) { return (r-1)*(c-1)*6%mod;}int main() { ll ans=0; int r=read(),c=read(),mn=read(),mx=read(); rep(i,2,r-1) rep(j,2,c-1) if(2*(i+j)>=mn&&2*(i+j)<=mx) (ans+=(ll)cal(i,j)*(r-i)*(c-j))%=mod; printf("%lld\n",ans); return 0;}
View Code

 

转载于:https://www.cnblogs.com/wzj-is-a-juruo/p/4935526.html

你可能感兴趣的文章