时间限制: 1 Sec 内存限制:128 MB
提交: 217 解决: 48
大家都知道,Glory不但知识水平高,并且非常喜欢思考,有一天Glory在思考一个问题,他在纸上写了两个1到n的排列,并且他想知道这两个排列的最大公共子序列的长度是多少,当然像Glory这么优秀的人当然一眼就看出了这个题目的答案,但是他太忙了,不想打这个代码,于是他扔给了他的小弟,但是他的小弟知识水平不够,所以他想找你萌帮帮他,你萌能帮他解决这个问题吗。
第一行一个数T,表示数据的测试组数(T<=5)
每组数据一个n,表示排列的长度(1<= n <= 1e5)
接下来两行,每行一个1~n的排列
对于每组数据,输出一个数表示最长公共子序列的长度。
2
2
1 2
1 2
3
1 3 2
2 3 1
2
1
由于是排列所以每个元素只出现一次。我们可以记录下来每个数 p 在第一个排列中出现的位置a[p] = i,在读第二个数列的时候把第二个排列中每个数 p 在第一个排列中出现的位置依次存在 b[] 中,即b[i] = a[p]。则 b[](位置序号)中的上升子序列对应的元素序列均为第一个排列的子序列,求 b[] 的最长上升子序列即可。
代码:
#include
#include
#include
usingnamespace std;
const int maxn = 1e5 + 5;
int a[maxn],b[maxn],c[maxn];
int main()
{
int t,n,p;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i = 1;i <= n; ++i)
{
scanf("%d",&p);
a[p] = i;
}
for(int i = 1;i <= n; ++i)
{
scanf("%d",&p);
b[i] = a[p];
}
int len = 1,j;
c[0] = 0;
for(int i = 1;i <= n; ++i)
{
j = lower_bound(c,c + len,b[i]) - c;
if(j == len) ++len;
c[j] = b[i];
}
printf("%d\n",len - 1);
}
return 0;
}
时间限制: 3 Sec 内存限制: 128 MB
提交: 235 解决: 20
Godv拿到了一个长度为n(1<=n<=1e5)的数列,数列中每个数ai都满足1<=ai<=1e9。
然后神奇的Godv对这个数列施加了魔法。“巴拉拉能量~~~~哈!~~”
数列在Godv的魔法的影响下,发生了如下的变化:
首先,对相邻数字两两相加,得到一个长为n-1的新数列a’,用伪代码表示如下
for i=1:n-1
a'[i]=a[i]+a[i+1]
用a'代替a
重复进行这样的操作,直到数列长度为1
现在聪明的Godv想考考你,最后剩下的数的大小是多少?由于Godv不喜欢大数,所以请将结果对1001取模后输出
多组数据,第一行为数据组数T(1<=T<=25)。每组数据第一行包含一个数n。第二行为这个数列,每两个数之间用空格隔开
每组数据输出一个数,即最后剩下的数。
21121 2
13
假设 n=3,初始数列为1 2 3
那么一次变化后,数列变成 3 5 (1+2=3,2+3=5)
再变一次后,变成8 (3+5=8)
ans=8%1001=8
推几次就可以发现(比赛的时候就没发现)结果为:
C(n - 1,0)* a0 + C(n - 1,1)* a1 + … + C(n - 1,n - 1)an-1
由于模数 1001 不是素数,需要用拓展 Lucas 求组合数,简单点就是把 1001 分解质因数,分别求了再用中国剩余定理合起来。
#include
#include
#include
#define ll long long
using namespace std;
const ll lcm = 1001;
const ll mod[3] = {7,11,13};
ll a[3];
ll Fastpow(ll a,ll b,ll mo)
{
ll ans = 1;
while(b > 0)
{
if(b & 1) ans = (ans * a) % mo;
b >>= 1;
a = (a * a) % mo;
}
return ans;
}
ll Getc(ll a,ll b,ll mo)
{
if(a < b)return 0;
if(b > a - b) b = a - b;
ll s1 = 1,s2 = 1;
for(ll i = 0;i < b; ++i)
{
s1 = s1 * (a - i) % mo;
s2 = s2 * (i + 1) % mo;
}
return s1 * Fastpow(s2,mo - 2,mo) % mo;
}
ll Lucas(ll n,ll k,ll mo)
{
if(k == 0)return 1;
return Getc(n % mo,k % mo,mo) * Lucas(n / mo,k / mo,mo) % mo;
}
ll Exgcd(ll a,ll b,ll &x,ll &y)
{
if(b == 0) x = 1,y = 0;
else
{
Exgcd(b,a % b,y,x);
y -= x * (a / b);
}
}
ll Calc(ll x,ll y)
{
ll ans = 0,M,m,temp;
for(inti = 0;i < 3; ++i)
{
temp = Lucas(x,y,mod[i]);
Exgcd(lcm / mod[i],mod[i],M,m);
ans = (ans + temp * M * (lcm / mod[i])) % lcm;
}
return ans;
}
int main()
{
ll t,n,temp;
scanf("%lld",&t);
while(t--)
{
ll ans = 0;
scanf("%lld",&n);
for(ll i = 0;i < n; ++i)
{
scanf("%lld",&temp);
ans = (ans + Calc(n - 1,i) * temp) % lcm;
}
printf("%lld\n",ans);
}
}
时间限制: 4 Sec 内存限制: 256 MB
提交: 68 解决: 11
5
1 2 3 4 5
1 2
1 3
3 4
3 5
5
1 3
1 4
3 1
3 3
2 1
3
4
3
5
2
主席树的模板题,不过这道不是直接求区间第 k 小,需要做一些处理。问的是以 x 为根的子树中的第 k 小。可以先将这棵树的 DFS 序用数组 po[] 存下来。对于一棵有根树,一棵子树的所有结点的 DFS 序在 po[] 中是一段连续的区间,对于每个点我们可以记录下来以它为根的子树中节点个数 sum[x],则每次查询 po[x] ~ (po[x] + sum[x] - 1) 中的第 k 小即可。P.S 主席树真是个神奇的数据结构。
#include
#include
#include
#include
#include
using namespace std;
const int MAXN = 100000 + 5;
const int M = MAXN * 30;
int n,q,m,tot;
int a[MAXN], t[MAXN];
int T[M], lson[M], rson[M],c[M];
void Init_hash()
{
for(inti = 1; i <= n;i++) t[i] = a[i];
sort(t+1,t+1+n);
m = unique(t+1,t+1+n)-t-1;
}
int build(int l,intr)
{
introot = tot++;
c[root] = 0;
if(l != r)
{
intmid = (l+r)>>1;
lson[root] = build(l,mid);
rson[root] = build(mid+1,r);
}
return root;
}
int Hash(int x)
{
return lower_bound(t+1,t+1+m,x) - t;
}
int update(int root,intpos,int val)
{
intnewroot = tot++, tmp = newroot;
c[newroot] = c[root] + val;
intl = 1, r = m;
while(l < r)
{
intmid = (l+r)>>1;
if(pos <= mid)
{
lson[newroot] = tot++; rson[newroot] = rson[root];
newroot = lson[newroot]; root = lson[root];
r = mid;
}
else
{
rson[newroot] = tot++; lson[newroot] = lson[root];
newroot = rson[newroot]; root = rson[root];
l = mid+1;
}
c[newroot] = c[root] + val;
}
return tmp;
}
int query(int left_root,intright_root,int k)
{
intl = 1, r = m;
while( l < r)
{
intmid = (l+r)>>1;
if(c[lson[left_root]]-c[lson[right_root]] >= k )
{
r = mid;
left_root = lson[left_root];
right_root = lson[right_root];
}
else
{
l = mid + 1;
k -= c[lson[left_root]] - c[lson[right_root]];
left_root = rson[left_root];
right_root = rson[right_root];
}
}
return l;
}
int cal;
int dfs[MAXN],po[MAXN],b[MAXN],sum[MAXN];
bool vis[MAXN];
vector g[MAXN];
int DFS(int x)
{
sum[x]++;
intlen = g[x].size();
for(inti = 0;i < len; ++i)
{
intu = g[x][i];
if(!vis[u])
{
vis[u] =true;
po[u] = cal,b[cal] = a[u],++cal;
sum[x] += DFS(u);
}
}
return sum[x];
}
int main()
{
while(scanf("%d",&n) != EOF)
{
tot = 0;
for(inti = 0;i <= n; ++i) g[i].clear();
memset(vis,false,sizeof(vis));
memset(sum,0,sizeof(sum));
for(inti = 1;i <= n;i++) scanf("%d",&a[i]);
intx,y;
for(inti = 1;i < n; ++i)
{
scanf("%d %d",&x,&y);
g[x].push_back(y);
g[y].push_back(x);
}
cal = 2;
po[1] = 1,b[1] = a[1],vis[1] = true;
DFS(1);
Init_hash();
T[n+1] = build(1,m);
for(inti = n;i ;i--)
{
intpos = Hash(b[i]);
T[i] = update(T[i+1],pos,1);
}
scanf("%d",&q);
while(q--)
{
intl,r,k,now;
scanf("%d %d",&now,&k);
l = po[now];
r = l + sum[now] - 1;
printf("%d\n",t[query(T[l],T[r+1],k)]);
}
}
return 0;
}