NOIP练习赛题目6
长途旅行 |
难度级别:A; 运行时间限制:3000ms; 运行空间限制:262144KB; 代码长度限制:2000000B |
试题描述
|
JY 是一个爱旅游的探险家,也是一名强迫症患者。现在JY 想要在C 国进行一次长途 旅行,C 国拥有n 个城市(编号为0,1,2...,n - 1),城市之间有m 条道路,可能某个城市到自己 有一条道路,也有可能两个城市之间有多条道路,通过每条道路都要花费一些时间。JY 从 0 号城市开始出发,目的地为n – 1 号城市。由于JY 想要好好参观一下C 国,所以JY 想要旅行恰好T 小时。为了让自己的旅行更有意思,JY 决定不在任何一个时刻停留(走一条到城市自己的路并不算停留)。JY 想知道是否能够花恰好T 小时到达n – 1 号城市(每个城市可经过多次)。现在这个问题交给了你。 若可以恰好到达输出“Possible”否则输出“Impossible”。(不含引号)。 |
输入
|
第一行一个正整数Case,表示数据组数。
每组数据第一行3 个整数,分别为n, m, T。 接下来m 行,每行3 个整数x, y, z,代表城市x 和城市y 之间有一条耗时为z 的双向边。 |
输出
|
对于每组数据输出”Possible”或者”Impossible”.
|
输入示例
|
2
3 3 11 0 2 7 0 1 6 1 2 5 2 1 10000 1 0 1 |
输出示例
|
Possible
Impossible |
其他说明
|
【样例解释】
第一组:0 -> 1 -> 2 :11 第二组:显然偶数时间都是不可能的。 【数据范围】 30%: T <= 10000 另有30%: n <= 5 , m <= 10. 100%: 2 <= n <= 50 , 1 <= m <= 100 , 1 <= z <= 10000 , 1 <= T <= 10^18 , Case <= 5. |
我还不懂哒。。。
hzwer的题解:http://hzwer.com/5006.html(然而我还不知道这个结论为什么是对的)
#include<cstdio>
#include<cctype>
#include<queue>
#include<cmath>
#include<cstring>
#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--)
#define ren for(int i=first[x];i;i=next[i])
using namespace std;
inline int read() {
int x=,f=;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-;
for(;isdigit(c);c=getchar()) x=x*+c-'';
return x*f;
}
typedef long long ll;
const int maxn=;
const int maxm=;
const int maxk=;
struct HeapNode {
int x,u,d;
bool operator < (const HeapNode& ths) const {return d>ths.d;}
};
int done[maxn][maxk],first[maxn],next[maxm],to[maxm],dist[maxm],n,m,mod,e;
ll d[maxn][maxk],T;
void AddEdge(int u,int v,int w) {
to[++e]=v;dist[e]=w;next[e]=first[u];first[u]=e;
to[++e]=u;dist[e]=w;next[e]=first[v];first[v]=e;
}
priority_queue<HeapNode> Q;
int dijkstra() {
rep(i,,n) rep(j,,mod) done[i][j]=,d[i][j]=1ll<<;
d[][]=;Q.push((HeapNode){,,});
while(!Q.empty()) {
int x=Q.top().x,u=Q.top().u;Q.pop();
if(done[x][u]) continue;done[x][u]=;
ren {
int u2=(u+dist[i])%mod;
if(d[x][u]+dist[i]<d[to[i]][u2]) {
d[to[i]][u2]=d[x][u]+dist[i];
Q.push((HeapNode){to[i],u2,d[to[i]][u2]});
}
}
}
return d[n][T%mod]<=T;
}
int main() {
dwn(Case,read(),) {
n=read();m=read();scanf("%lld",&T);mod=e=;
memset(first,,sizeof(first));
rep(i,,m) {
int u=read()+,v=read()+,w=read();
AddEdge(u,v,w);if(u==||v==) mod=w<<;
}
if(!mod) puts("Impossible");
else if(dijkstra()) puts("Possible");
else puts("Impossible");
}
return ;
}
数列 |
难度级别:A; 运行时间限制:1000ms; 运行空间限制:51200KB; 代码长度限制:2000000B |
试题描述
|
Czy 手上有一个长度为n 的数列,第i 个数为xi。 他现在想知道,对于给定的a,b,c,他要找到一个i,使得 a*(i+1)*xi2+(b+1)*i*xi+(c+i)=0 成立。 如果有多个i 满足,Czy 想要最小的那个i。 Czy 有很多很多组询问需要你回答,多到他自己也不确定有多少组。所以在输入数据中a=b=c=0 标志着Czy 的提问的结束。 更加糟糕的是,Czy 为了加大难度,决定对数据进行加密以防止离线算法的出现。 假设你在输入文件中读到的三个数为a0,b0,c0,那么Czy 真正要询问的a=a0+LastAns,b=b0+LastAns,c=c0+LastAns. LastAns 的值是你对Czy 的前一个询问的回答。如果这是第一个询问,那么LastAns=0。 所有的询问都将会按上述方式进行加密,包括标志着询问的结束的那个询问也是这样。 |
输入
|
输入文件为 seq.in
输入文件第一行包含一个整数n,表示数列的长度。 输入文件第二行包含n 个整数,第i 个数表示xi 的值。 接下来若干行,每行三个数,表示加密后的a,b,c 值(也就是上文所述的a0,b0,c0) |
输出
|
输出文件为 seq.out
包含若干行,第i 行的值是输入文件中第i 个询问的答案。注意,你不需要对标志着询问结束的那个询问作答。 同时,标志着询问结束的询问一定是输入文件的最后一行。也就是,输入文件不会有多余的内容。 |
输入示例
|
5
-2 3 1 -5 2 -5 -4 145 -1 -6 -509 -9 -14 40 -3 -13 21 -3 -3 -3 |
输出示例
|
5
4 3 3 |
其他说明
|
【数据范围】
对于40%的数据,满足N<=1000,需要作出回答的询问个数不超过1000. 对于100%的数据,满足N<=50000,需要作出回答的询问个数不超过500000,xi 的绝对值不 超过30000,解密后的a 的绝对值不超过50000,解密后的b 的绝对值不超过10^8,解密后的c 的绝对值不超过10^18. |
好逗的一道题。。。
注意结尾肯定是0 0 0,那么倒数第二个问题的答案可以推出来,然后倒数第三个问题的答案可以推出来。。。。
#include<cstdio>
#include<cctype>
#include<queue>
#include<cmath>
#include<cstring>
#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--)
#define ren for(int i=first[x];i!=-1;i=next[i])
using namespace std;
typedef long long ll;
inline ll read() {
ll x=,f=;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-;
for(;isdigit(c);c=getchar()) x=x*+c-'';
return x*f;
}
const int maxn=;
int n,m=,v[maxn];
ll A[maxn],B[maxn],C[maxn],res[maxn],ans;
int main() {
n=read();
rep(i,,n) v[i]=read();
while(scanf("%lld%lld%lld",&A[m],&B[m],&C[m])==) m++;m--;
res[m]=ans=-A[m];
dwn(k,m-,) {
ll xi=v[ans],i=ans;
ll t1=A[k]*(i+)*xi*xi+(B[k]+)*i*xi+(C[k]+i);
ll t2=(i+)*xi*xi+i*xi+;
res[k]=ans=-t1/t2;
}
rep(i,,m) printf("%lld\n",res[i]);
return ;
}
刷漆 |
难度级别:A; 运行时间限制:1000ms; 运行空间限制:262144KB; 代码长度限制:2000000B |
试题描述
|
Czy 做完了所有的回答出了所有的询问,结果是,他因为脑力消耗过大而变得更虚了:)。帮助Czy 恢复身材的艰巨任务落到了你的肩上。 正巧,你的花园里有一个由N 块排成一条直线的木板组成的栅栏,木板从左到右依次标号1到N。这N 块木板中,有M 块木板前面放着一桶油漆。油漆有不同的颜色,每种颜色可以由一个大写字母表示(A 到Z)。而你要求Czy 用他的油漆刷子给栅栏刷上油漆。 已知Czy 会选择一个前方放有油漆桶的木板开始他的任务。刷子蘸上油漆后,他开始随机地沿着栅栏走,他不会走出栅栏的范围。随机地走表示Czy 会沿着他选择的方向一直走,然后随机在任何时候改变方向。沿着栅栏走只有两个方向,向前和向后。 你发现Czy 刷油漆的过程总是符合下列规则: • 每个油漆桶里装着无限多的油漆; • 刷子上每次只有一种颜色的油漆,每次蘸油漆都会完全替换刷子上的油漆颜色; • 当Czy 走到一个油漆桶前,他会首先用刷子蘸这个油漆桶里的油漆; • Czy 每走过一个木板都会将这个木板刷成当前刷子上的油漆颜色。 已知木板可以被多次刷上油漆,每次都会完全覆盖之前的颜色。当所有木板都被刷上了油漆的时候,Czy 才能停下来(当然他也可以继续刷到他想停下来为止)。你看着Czy 在栅栏前来回舞动,突然想知道Czy 停下来的时候栅栏有多少种可能的不同油漆方案。定义当至少有一块木板颜色不同时,两种油漆方案被视为是不同的。 请你输出不同的油漆方案数对10^9+9 取模的值。 |
输入
|
输入的第一行包含两个整数N 和M。
接下来M 行,每行两个整数x 和y,表示第y 块木板前面有一个装着颜色为x 的油漆的油漆桶。 |
输出
|
输出一行,包含一个整数,表示不同的油漆方案数对10^9 + 9 取模的结果。
|
输入示例
|
6 2
A 2 B 6 |
输出示例
|
4
|
其他说明
|
【数据范围】
对于30% 的数据,1 ≤ M ≤ N ≤ 100。 对于100% 的数据, 1 ≤ M ≤ N ≤ 100000。 x 是A 到Z 之间的大写字母;1 ≤ y ≤ N。 |
可以将整个线段分成若干段,若i、j均是油漆桶,且Ai!=Aj,则这区间共有j-i种方案,乘起来就行了。
#include<cstdio>
#include<cctype>
#include<queue>
#include<cmath>
#include<cstring>
#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--)
#define ren for(int i=first[x];i!=-1;i=next[i])
using namespace std;
inline int read() {
int x=,f=;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-;
for(;isdigit(c);c=getchar()) x=x*+c-'';
return x*f;
}
const int maxn=;
const int mod=;
long long ans=;
int A[maxn];
int main() {
int n=read(),m=read();
rep(i,,m) {
char c[];scanf("%s",c);
int p=read();
A[p]=c[]-'A'+;
}
rep(i,,n) if(A[i]) {A[]=A[i];break;}
dwn(i,n,) if(A[i]) {A[n+]=A[i];break;}
rep(i,,n) {
int j=i+;
while(j<=n+&&!A[j]) j++;
if(A[i]!=A[j]) (ans*=(j-i))%=mod;
i=j-;
}
printf("%lld\n",ans);
return ;
}
排队 |
难度级别:A; 运行时间限制:1000ms; 运行空间限制:51200KB; 代码长度限制:2000000B |
试题描述
|
Czy 喜欢将他的妹子们排成一队。假设他拥有N 只妹纸,编号为1 至N。Czy 让他们站成一行,等待自己来派送营养餐。这些妹纸按照编号大小排列,并且由于它们都很想早点吃饭,于是就很可能出现多只妹纸挤在同一位置的情况(也就是说,如果我们认为妹纸位于数轴上,那么多只妹纸的位置坐标可能相同)。 因为众所周知的原因,某些妹纸之间互相喜欢,他们希望互相之间的距离至多为一个定值。 但某些妹纸之间互相厌恶,他们希望互相之间的距离至少为一个定值。现在给定ML 个互相喜爱的妹纸对以及他们之间距离的最大值,MD 个互相厌恶的妹纸对以及他们之间距离的最小值。 你的任务是计算在满足以上条件的前提下,帮助Czy 计算出编号为1 和编号为N 的妹纸之间距离的最大可能值。 |
输入
|
输入文件为 layout.in。
第一行有 3 个整数,每两个整数之间用一个空格隔开,依次表示 n,ML 和DL ; 此后ML 行,每行包含三个用空格分开的整数A,B 和D,其中A,B 满足1<=A<=B<=N。表示编号为A 和B 的妹纸之间的距离至多为D。 此后MD 行,每行包含三个用空格分开的整数A,B 和D,其中A,B 满足1<=A<=B<=N。表示编号为A 和B 的妹纸之间的距离至少为D。 |
输出
|
输出文件名为 layout.out。
输出文件仅包含一个整数。如果不存在任何合法的排队方式,就输出‐1。如果编号1 和编号N 的妹纸间距离可以任意,就输出‐2 。否则输出他们之间的最大可能距离。 |
输入示例
|
4 2 1
1 3 10 2 4 20 2 3 3 |
输出示例
|
27
|
其他说明
|
【数据范围】
对于40%的数据,N<=100; 对于100%的数据,N<=1000;ML,MN<=10000;D<=1000000。 |
又是查分约束系统
#include<cstdio>
#include<cctype>
#include<queue>
#include<cmath>
#include<cstring>
#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--)
#define ren for(int i=first[x];i;i=next[i])
using namespace std;
inline int read() {
int x=,f=;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-;
for(;isdigit(c);c=getchar()) x=x*+c-'';
return x*f;
}
typedef long long ll;
const int maxn=;
const int maxm=;
const ll INF=1e16;
int n,first[maxn],to[maxm],dist[maxm],next[maxm],e;
void AddEdge(int u,int v,int w) {
to[++e]=v;dist[e]=w;next[e]=first[u];first[u]=e;
}
int inq[maxn],q[maxn],cnt[maxn];
ll d[maxn];
int spfa() {
rep(i,,n) d[i]=INF;
int l=,r=;q[]=;
while(l!=r) {
int x=q[l++];if(l==) l=;inq[x]=;
ren if(d[to[i]]>d[x]+dist[i]) {
d[to[i]]=d[x]+dist[i];
if(++cnt[to[i]]>n) return -;
if(!inq[to[i]]) {
inq[to[i]]=;
q[r++]=to[i];if(r==) r=;
}
}
}
return d[n]==INF?-:d[n];
}
int main() {
n=read();int m1=read(),m2=read();
rep(i,,m1) {
int a=read(),b=read(),c=abs(read());
AddEdge(a,b,c);
}
rep(i,,m2) {
int a=read(),b=read(),c=abs(read());
AddEdge(b,a,-c);
}
printf("%d\n",spfa());
return ;
}
感冒病毒 |
难度级别:A; 运行时间限制:1000ms; 运行空间限制:51200KB; 代码长度限制:2000000B |
试题描述
|
一种感冒病毒正在学校里传播,这所学校有n个学生,m个学生社团,每个学生可能参加了多个社团,因为同一个社团的学生交流较多,所以如果一个学生感染上感冒病毒,那么他所在的社团里的所有学生都会感染上感冒病毒,现在已知0号学生感染上感冒病毒,问现在有多少人会感染上感冒病毒。
|
输入
|
输入文件:suspects.in
输入的第一行是两个整数n和m,表示学生的数目和社团的数目,学生的编号为0到n-1。 接下来m行,每行首先是一个数ki,表示这个社团有ki个人,接下来ki个整数,表示这个社团里每个学生的编号aij。 |
输出
|
输出文件:suspects.out
输出为一行,包含一个整数。表示感染感冒病毒的人数。 |
输入示例
|
100 4
2 1 10 5 10 13 11 12 14 2 0 1 2 9 2 |
输出示例
|
7
|
其他说明
|
【数据范围】
对于100%的数据,3<=n<=30000 对于100%的数据,3<=m<=500 对于100%的数据,1<=ki<=n 对于100%的数据,0<=aij<n。 |
。。。
#include<cstdio>
#include<cctype>
#include<queue>
#include<cmath>
#include<cstring>
#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--)
#define ren for(int i=first[x];i!=-1;i=next[i])
using namespace std;
inline int read() {
int x=,f=;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-;
for(;isdigit(c);c=getchar()) x=x*+c-'';
return x*f;
}
const int maxn=;
int n,m,pa[maxn];
int findset(int x) {return x==pa[x]?x:pa[x]=findset(pa[x]);}
int main() {
n=read();m=read();
rep(i,,n) pa[i]=i;
rep(i,,m) {
int k=read(),x=read()+;
while(--k) pa[findset(x)]=findset(read()+);
}
int ans=;
rep(i,,n) if(findset(i)==findset()) ans++;
printf("%d\n",ans);
return ;
}
弱点 |
难度级别:A; 运行时间限制:1000ms; 运行空间限制:51200KB; 代码长度限制:2000000B |
试题描述
|
一队勇士正在向你进攻,每名勇士都有一个战斗值ai。但是这队勇士却有一个致命弱点,如果存在i<j<k使得ai>aj>ak,则会影响他们整体的战斗力。我们将这样的一组(i,j,k)称为这队勇士的一个弱点。请求出这队勇士的弱点数目。
|
输入
|
输入文件:weakness.in
输入的第一行是一个整数n,表示勇士的数目。 接下来一行包括n个整数,表示每个勇士的战斗值ai。 |
输出
|
输入文件:weakness.out
输出为一行,包含一个整数。表示这队勇士的弱点数目。 |
输入示例
|
4
10 8 3 1 |
输出示例
|
4
|
其他说明
|
【数据范围】
对于30%的数据,3<=n<=100 对于100%的数据,3<=n<=1000000 对于100%的数据,1<=ai<=1000000,每个ai均不相同 |
对于每个位置,求出有多少在其左边的数<Ai,有多少在其右边的数>Ai。用个Fenwich就行了。
#include<cstdio>
#include<cctype>
#include<queue>
#include<cmath>
#include<cstring>
#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--)
#define ren for(int i=first[x];i!=-1;i=next[i])
using namespace std;
inline int read() {
int x=,f=;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-;
for(;isdigit(c);c=getchar()) x=x*+c-'';
return x*f;
}
typedef long long ll;
const int maxn=;
ll ans;
int n,A[maxn],f[maxn],c[maxn];
int query(int x) {
int res=;
for(;x;x-=x&-x) res+=c[x];
return res;
}
void add(int x,int v) {
for(;x<=;x+=x&-x) c[x]+=v;
}
int main() {
n=read();rep(i,,n) A[i]=read();
rep(i,,n) {
add(A[i],);
f[i]=i-query(A[i]);
}
memset(c,,sizeof(c));
dwn(i,n,) {
add(A[i],);
ans+=(ll)query(A[i]-)*f[i];
}
printf("%lld\n",ans);
return ;
}
改造二叉树 |
难度级别:A; 运行时间限制:1000ms; 运行空间限制:51200KB; 代码长度限制:2000000B |
试题描述
|
小Y在学树论时看到了有关二叉树的介绍:在计算机科学中,二叉树是每个结点最多有两个子结点的有序树。通常子结点被称作“左孩子”和“右孩子”。二叉树被用作二叉搜索树和二叉堆。随后他又和他人讨论起了二叉搜索树。 什么是二叉搜索树呢?二叉搜索树首先是一棵二叉树。设key[p]表示结点p上的数值。对于其中的每个结点p,若其存在左孩子lch,则key[p]>key[lch];若其存在右孩子rch,则key[p]<key[rch];注意,本题中的二叉搜索树应满足对于所有结点,其左子树中的key小于当前结点的key,其右子树中的key大于当前结点的key。 小Y与他人讨论的内容则是,现在给定一棵二叉树,可以任意修改结点的数值。修改一个结点的数值算作一次修改,且这个结点不能再被修改。若要将其变成一棵二叉搜索树,且任意时刻结点的数值必须是整数(可以是负整数或0),所要的最少修改次数。 相信这一定难不倒你!请帮助小Y解决这个问题吧。 |
输入
|
第一行一个正整数n表示二叉树结点数。结点从1~n进行编号。
第二行n个正整数用空格分隔开,第i个数ai表示结点i的原始数值。 此后n - 1行每行两个非负整数fa, ch,第i + 2行描述结点i + 1的父亲编号fa,以及父子关系ch,(ch = 0 表示i + 1为左儿子,ch = 1表示i + 1为右儿子)。 结点1一定是二叉树的根。 |
输出
|
仅一行包含一个整数,表示最少的修改次数。
|
输入示例
|
3
2 2 2 1 0 1 1 |
输出示例
|
2
|
其他说明
|
【数据范围】
20 % :n <= 10 , ai <= 100. 40 % :n <= 100 , ai <= 200 60 % :n <= 2000 . 100 % :n <= 10 ^ 5 , ai < 2 ^ 31. |
先将二叉树中序遍历,然后参见"Incr"。
#include<cstdio>
#include<cctype>
#include<queue>
#include<stack>
#include<cstring>
#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--)
#define ren for(int i=first[x];i!=-1;i=next[i])
using namespace std;
inline int read() {
int x=,f=;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-;
for(;isdigit(c);c=getchar()) x=x*+c-'';
return x*f;
}
const int maxn=;
int n,ans,cnt,vis[maxn],A[maxn],g[maxn],val[maxn],ls[maxn],rs[maxn];
int S[maxn],top;
void dfs(int x) {
S[++top]=x;
while(top) {
x=S[top];
if(!vis[x]) {
vis[x]=;
if(ls[x]) S[++top]=ls[x];
}
else {
A[++cnt]=val[x];top--;
if(rs[x]) S[++top]=rs[x];
}
}
}
int main() {
n=read();rep(i,,n) val[i]=read();
rep(i,,n) {
int f=read(),t=read();
if(!t) ls[f]=i;
else rs[f]=i;
}
dfs();
rep(i,,n) A[i]-=i,g[i]=2e9;
rep(i,,n) {
int k=upper_bound(g+,g+n+,A[i])-g;
ans=max(ans,k);g[k]=A[i];
}
printf("%d\n",n-ans);
return ;
}
数字对 |
难度级别:A; 运行时间限制:3000ms; 运行空间限制:262144KB; 代码长度限制:2000000B |
试题描述
|
小H是个善于思考的学生,现在她又在思考一个有关序列的问题。 她的面前浮现出一个长度为n的序列{ai},她想找出一段区间[L, R](1 <= L <= R <= n)。 这个特殊区间满足,存在一个k(L <= k <= R),并且对于任意的i(L <= i <= R),ai都能被ak整除。这样的一个特殊区间 [L, R]价值为R - L。 小H想知道序列中所有特殊区间的最大价值是多少,而有多少个这样的区间呢?这些区间又分别是哪些呢?你能帮助她吧。 |
输入
|
第一行,一个整数n.
第二行,n个整数,代表ai. |
输出
|
第一行两个整数,num和val,表示价值最大的特殊区间的个数以及最大价值。
第二行num个整数,按升序输出每个价值最大的特殊区间的L. |
输入示例
|
【样例输入1】
5 4 6 9 3 6 【样例输入2】 5 2 3 5 7 11 |
输出示例
|
【样例输出1】
1 3 2 【样例输出2】 5 0 1 2 3 4 5 |
其他说明
|
【数据范围】
30%: 1 <= n <= 30 , 1 <= ai <= 32. 60%: 1 <= n <= 3000 , 1 <= ai <= 1024. 80%: 1 <= n <= 300000 , 1 <= ai <= 1048576. 100%: 1 <= n <= 500000 , 1 <= ai < 2 ^ 31. |
枚举k,则问题转化成找最大的区间[l,r]满足对于任意的i(L <= i <= R),ai都能被ak整除。
如果我们能实现一个快速计算区间gcd的数据结构,就可以用二分答案的方法O(logn)得出答案。
直接上ST表就行了。
#include<cstdio>
#include<cctype>
#include<queue>
#include<cmath>
#include<cstring>
#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--)
#define ren for(int i=first[x];i!=-1;i=next[i])
using namespace std;
inline int read() {
int x=,f=;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-;
for(;isdigit(c);c=getchar()) x=x*+c-'';
return x*f;
}
int gcd(int a,int b) {return !b?a:gcd(b,a%b);}
const int maxn=;
int n,first,A[maxn],f[maxn],yes[maxn],g[maxn],Log[maxn],res[maxn][];
void init() {
Log[]=-;
rep(i,,n) Log[i]=Log[i>>]+;
rep(i,,n) res[i][]=A[i];
for(int j=;(<<j)<=n;j++)
for(int i=;i+(<<j)-<=n;i++)
res[i][j]=gcd(res[i][j-],res[i+(<<j-)][j-]);
}
int query(int l,int r) {
int k=Log[r-l+];
return gcd(res[l][k],res[r-(<<k)+][k]);
}
int main() {
n=read();rep(i,,n) A[i]=read();
init();
rep(i,,n) {
int l=,r=i;
while(l<r) {
int mid=l+r>>;
if(query(mid,i)%A[i]==) r=mid;
else l=mid+;
}
f[i]=l;
}
dwn(i,n,) {
int l=i,r=n+;
while(l+<r) {
int mid=l+r>>;
if(query(i,mid)%A[i]==) l=mid;
else r=mid;
}
g[i]=l;
}
int ans=,cnt=;
rep(i,,n) ans=max(ans,g[i]-f[i]);
rep(i,,n) if(ans==g[i]-f[i]) yes[f[i]]=;
rep(i,,n) if(yes[i]) cnt++;
printf("%d %d\n",cnt,ans);
rep(i,,n) if(yes[i]) {
if(!first) first=;
else putchar(' ');
printf("%d",i);
}
return ;
}
篮球比赛1 |
难度级别:A; 运行时间限制:1000ms; 运行空间限制:51200KB; 代码长度限制:2000000B |
试题描述
|
Czhou为了提高机房里各种神牛的身体素质,决定在每次训练后举行篮球比赛。为了保持比赛公平,Czhou要将神牛们分成两队。首先神牛们赛前都要排成固定的队伍;然后Czhou将队伍分成一半(前一半和后一半队伍人数可以不等),再分别从两个队伍中选出一些人进行篮球比赛。为了保持公平性,Czhou要求第一个队伍参加比赛的神牛能力的XOR值等于第二个队伍参加比赛的神牛能力的and值。为了增加比赛趣味,每次比赛的参加神牛们不能一样,Czhou现在想知道可以举办多少天的比赛。(很明显参加比赛的人数不能为0) Xor即为亦或, 0 xor 0 = 0, 0 xor 1 = 1, 1 xor 0 = 1 , 1 xor 1 = 0。 And即为与, 0 and 0 = 0, 0 and 1 = 0, 1 and 0 = 0, 1 and 1 = 1。 举个例子10 and 2 = 10,10 xor 2 = 8, 10 = (1010)2 2 = (10)2 8 =(1000)2 |
输入
|
第一行n,表示机房有n个神牛。
第二行有n个数a_i,表示各个神牛的能力值,并且这是赛前各个神牛的排队方式。 |
输出
|
就一个数字,表示可以举办多少天比赛。由于天数会比较多,输出结果模1000000007。
|
输入示例
|
Sample1.input:
3 1 2 3 Sample2.input 4 1 2 3 3 |
输出示例
|
Sample1.output
1 Sample2.output 4 |
其他说明
|
样例1说明:1 xor 2 = 3
样例2说明:可以举办四天比赛,参加比赛的双方队伍分别是(1,2)(3);(1,2)(3);(1,2)(3,3);(3)(3)这里虽然能力值相同,但是指的是不同的牛。 对于(1,2)(3,3)来说,队伍分为两个队伍:(1,2)(3,3),再从各自队伍选出全部选手参加比赛 对于(3)(3)来说,队列分为两个队伍:(1,2,3)(3),再从各自队伍中选出3进行比赛 数据范围: |
重复了。。。
#include<cstdio>
#include<cctype>
#include<queue>
#include<cmath>
#include<cstring>
#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--)
#define ren for(int i=first[x];i!=-1;i=next[i])
using namespace std;
inline int read() {
int x=,f=;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-;
for(;isdigit(c);c=getchar()) x=x*+c-'';
return x*f;
}
typedef long long ll;
const int maxn=;
const int maxk=;
const int mod=;
ll f[maxn][maxk][],g[maxn][maxk][];
int n,A[maxn];
int main() {
n=read();rep(i,,n) A[i]=read();
rep(i,,n) {
f[i][A[i]][]++;
rep(j,,) {
(f[i][j][]+=f[i-][j][]+f[i-][j][])%=mod;
(f[i][j^A[i]][]+=f[i-][j][]+f[i-][j][])%=mod;
}
}
dwn(i,n,) {
g[i][A[i]][]++;
rep(j,,) {
(g[i][j][]+=g[i+][j][]+g[i+][j][])%=mod;
(g[i][j&A[i]][]+=g[i+][j][]+g[i+][j][])%=mod;
}
}
ll ans=;
rep(i,,n-) rep(j,,) (ans+=(f[i][j][]*(g[i+][j][]+g[i+][j][]))%mod)%=mod;
printf("%lld\n",ans);
return ;
}
篮球比赛2 |
难度级别:A; 运行时间限制:1000ms; 运行空间限制:262144KB; 代码长度限制:2000000B |
试题描述
|
由于Czhou举行了众多noip模拟赛,也导致放学后篮球比赛次数急剧增加。神牛们身体素质突飞猛进,并且球技不断精进。这引起了体育老师彩哥的注意,为了给校篮球队找到势均力敌的对手,彩哥找到了Czhou神,想要和机房篮球队进行多场友谊赛。Czhou为了顾全校篮球队面子,决定派出配合默契又不至于吊打校篮球队的阵容。 而机房神牛的能力值受到游戏时长,训练时长,个人基础值得影响,可能会不断变化。所以Czhou想根据神牛当天状态从中选出若干名选手,使他们的能力值和等于k。 |
输入
|
一行三个数n,k,l。表示机房有n个神牛,选出队员能力值和为k,每个神牛的能力最大值<=L且>=0。
|
输出
|
输出一个数,表示方案数,方案满足选出若干选手使能力和为k。因为答案比较大,最后模10^9+7。
|
输入示例
|
2 2 2
|
输出示例
|
6
|
其他说明
|
样例说明:神牛的能力值可能为(0,2)(1,2)(1,1)(2,0)(2,1)(2,2),这样都可以选出一些数字使他们的能力值和为2。
对于(0,2)表示第一只牛能力值为0,第二只牛能力为2 类似的 对于(1,2)选出2即满足要求。 对于(1,1)选出全部选手即满足要求。 所以(0,2)(1,1)都是满足要求的方案。 数据范围: n,k<=20 0<=L<=10^9. |
状压DP,设f[i][S]表示前i个神牛,目前选出的队员能够合成能力在S集合中的方案数。
转移就很简单了。
#include<cstdio>
#include<cctype>
#include<queue>
#include<cmath>
#include<cstring>
#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--)
#define ren for(int i=first[x];i!=-1;i=next[i])
using namespace std;
inline int read() {
int x=,f=;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-;
for(;isdigit(c);c=getchar()) x=x*+c-'';
return x*f;
}
typedef long long ll;
const int mod=;
ll f[][<<];
int n,k,l;
int main() {
n=read();k=read()+;l=read();
int cur=,all=(<<k)-;f[][]=;
rep(i,,n) {
cur^=;
rep(S,,all) f[cur][S]=;
rep(S,,all) if(f[cur^][S]) {
rep(j,,min(k-,l)) (f[cur][(S|(S<<j)|(<<j))&all]+=f[cur^][S])%=mod;
if(l>=k) (f[cur][S]+=f[cur^][S]*(l-k+))%=mod;
}
}
ll ans=;
rep(S,,all) if(S>>k-&) (ans+=f[cur][S])%=mod;
printf("%lld\n",ans);
return ;
}
NOIP练习赛题目6的更多相关文章
- NOIP练习赛题目5
小象涂色 难度级别:C: 运行时间限制:1000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 小象喜欢为箱子涂色.小象现在有c种颜色,编号为0~c-1:还有n个箱 ...
- NOIP练习赛题目3
魔兽争霸 难度级别:C: 运行时间限制:1000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 小x正在销魂地玩魔兽他正控制着死亡骑士和n个食尸鬼(编号1-n)去打 ...
- NOIP练习赛题目1
有些题目可能没做,如计算几何.恶心模拟. 高级打字机 难度级别:C: 运行时间限制:1000ms: 运行空间限制:51200KB: 代码长度限制:2000000B 试题描述 早苗入手了最新的高级打字机 ...
- NOIP练习赛题目4
肥得更高 难度级别:C: 运行时间限制:1000ms: 运行空间限制:51200KB: 代码长度限制:2000000B 试题描述 自2009年以来,A.B站的历史就已经步入了农业变革的黎明期.在两站的 ...
- NOIP练习赛题目2
小K的农场 难度级别:C: 运行时间限制:1000ms: 运行空间限制:51200KB: 代码长度限制:2000000B 试题描述 小K在MC里面建立很多很多的农场,总共n个,以至于他自己都忘记了每个 ...
- 【NOIP练习赛】开车
[NOIP练习赛]T2.开车 Description 老司机小 Q 要在一个十字路口指挥车队开车,这个十字路口可 以描述为一个 n*n 的矩阵,其中第 2 行到第 n-1 行都各有一道横向车 道,第 ...
- Noip往年题目整理
Noip往年题目整理 张炳琪 一.历年题目 按时间倒序排序 年份 T1知识点 T2知识点 T3知识点 得分 总体 2016day1 模拟 Lca,树上差分 期望dp 144 挺难的一套题目,偏思维难度 ...
- 【NOIP练习赛】学习
[NOIP练习赛]T3.学习 Description 巨弱小 D 准备学习,有 n 份学习资料给他看,每份学习资料的 内容可以用一个正整数 ai 表示.小 D 如果在一天内学习了多份资料, 他只能记住 ...
- NOIp初赛题目整理
NOIp初赛题目整理 这个 blog 用来整理扶苏准备第一轮 csp 时所做的与 csp 没 有 关 系 的历年 noip-J/S 初赛题目,记录了一些我从不知道的细碎知识点,还有一些憨憨题目,不定期 ...
随机推荐
- BZOJ2301:莫比乌斯反演+二维容斥解决GCD范围计数
这个题是刚才刷的第一道反演题的拓展版,加上一个容斥就可以了 #include<cstdio> #include<algorithm> using std::min; ; int ...
- MySql数据库资料收集
1.下载MySQL历史版本 https://downloads.mysql.com/archives/community/ https://downloads.mysql.com/archives/i ...
- IOS 与 PHP 通信加密,使用AES 128 CBC no padding
这个网上的资料真实浩如烟海,但是真正有价值的屈指可数 自己尝试了一天多,终于还是搞定了. 再次要感谢网上的前辈么. 比如下面这个关于php和java端的实现: http://my.oschina.ne ...
- 有关楼层滚动且对应楼层Nav导航高亮显示
$(document).ready(function(e) { //定义数组,储存楼层距离顶部的高度(floorsTop) var floorsTop=[]; function floorsTopF( ...
- cas单点登录实现
前言 此文为记录单点登录实现过程,包括cas服务端和客户端的定制扩展 服务端 单点登录服务端采用cas,以cas-server-webapp版本号为3.5.2.1为基础进行定制扩展实现. 定制实现的源 ...
- 【问题收集·知识储备】Xcode只能选择My Mac,不能选择模拟器如何解决?
网友问题:请问打开一个应用,只能选择My Mac,不能选择模拟器如何解决? 答案: 下面将问答过程记录如下: CHENYILONG Blog 请问打开一个应用,只能 ...
- Linux笔记之如何分割文件或管道流:split
一.简介 在Linux中合并文件可以使用cat命令,后面跟上要合并的文件然后重定向到一个新的文件中即可,甚至可以追加合并.但如果要将一个大文件分割为多个小文件应该如何操作呢? 在Linux的coreu ...
- idea-plugin
codehelper.generator https://github.com/zhengjunbase/codehelper.generator?id=5f5b0005-11fb-48e4-bdb7 ...
- 搭建RabbitMQ集群(Docker)
前一篇搭建RabbitMQ集群(通用)只是把笔记直接移动过来了,因为我的机器硬盘已经满了,实在是开不了那么虚拟机. 还好,我的Linux中安装了Docker,这篇文章就简单介绍一下Docker中搭建R ...
- 用《舌尖2》去理解C#中的多态和开闭原则
昨天晚上看了<舌尖上的中国2>第一集,特别的感人,尤其是看到帮别人割麦子的麦客,一亩地开价200,雇主只肯给100,脸上的那种纠结和无可奈何.还有长着大眼睛的跳跳鱼,很可爱,不过最终还是被 ...