T1
描述
给定3个字符串,求它们的最长公共子序列。
输入
第一行一个整数n,表示三个字符串的长度
接下来三行,每行是一个长度为n只包含小写字母的字符串。
输出
输出最长公共子序列的长度。
输入样例
4
abac
abbc
cbca
输出样例
2
提示
30% n<=10
100% n<=120
水水水
#include
#include
#include
using namespace std;
const int N=125;
int f[N][N][N],n;
char a[N],b[N],c[N];
int main()
{
freopen("subq.in","r",stdin);
freopen("subq.out","w",stdout);
scanf("%d",&n);
scanf("%s",a+1);scanf("%s",b+1);scanf("%s",c+1);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
if(a[i]==b[j]&&b[j]==c[k])
f[i][j][k]=f[i-1][j-1][k-1]+1;
else{
int ma=max(f[i-1][j][k],f[i][j-1][k]);
ma=max(ma,f[i][j][k-1]);
ma=max(ma,f[i-1][j-1][k]);
ma=max(ma,f[i-1][j][k-1]);
ma=max(ma,f[i][j-1][k-1]);
f[i][j][k]=ma;
}
printf("%d\n",f[n][n][n]);
return 0;
}
T2
【问题描述】
定义两个素数是连续的当且仅当这两个素数之间不存在其他的素数(如 7,11 ,(23,29)。给定��,��,在不超过��的正整数中求能够分解为��个连续的素数的和的最大的那个是多少。
【输入格式】
第一行一个正整数��代表数据组数。
接下来��行每行两个正整数��,��代表一组询问。
【输出格式】
输出共��行,每行一个整数代表答案;如果找不到这样的数,输出−1。
【样例输入】
3
20 2
20 3
20 4
【样例输出】
18
15
17
【样例解释】
╭︿︿︿╮
{/ o o /}
( (oo) )
︶︶︶
【数据规模与约定】
对于20%的数据,1≤��≤100。
对于40%的数据,��=1。
对于60%的数据,所有的询问的��相等。
对于100%的数据,1≤��<2000,1≤��≤106
这道题,拿到之后第一个反应是找规律啊找规律,发现没有规律可以找…然后干脆写个暴力吧…嗯暴力时顺手一个前缀和….咦不如写二分?…..哇刚好能过诶!<-这就是我做这道题的全过程orz
代码:
#include
#include
#define LL long long
using namespace std;
const int N=2005;
LL zhi[78500];
int t,tot,n,ans,k;
bool a[1000005];
struct node{
int q,n;
};
void pre()
{
for(int i=2;i<=1000000;i++)
if(!a[i])
for(LL j=(LL)i*i;j<=1000000;j+=i)
a[j]=true;
for(int i=2;i<=1000000;i++)
if(!a[i])zhi[++tot]=zhi[tot-1]+i;
}
void sear(int le,int ri)
{
ans=-1;
while(le<=ri)
{
int mid=(le+ri)>>1;
LL sum=zhi[mid]-zhi[max(0,mid-k)];
if(sum<=(LL)n)le=mid+1,ans=(int)sum;
else ri=mid-1;
}
}
void worrk()
{
scanf("%d",&t);
for(int i=1;i<=t;i++)
{
scanf("%d%d",&n,&k);
if(zhi[k]>n){printf("-1\n");continue;}
sear(max(1,2*k-tot),tot);
printf("%d\n",ans);
}
}
int main()
{
freopen("dun.in","r",stdin);
freopen("dun.out","w",stdout);
pre();
worrk();
}
T3
发放粮食
描述
有一个村庄在闹饥荒,善良而土豪的YGH决定给他们发放救济粮,该村庄有 n 户人家,每两户人家之间只有一条路可以互相到达,即这些人家之间形成一棵树。现在 YGH 会以这样的形式给他们发放粮食,选择两户人家,然后对这两个户人家路径上的所有人家都发放一袋种类为 w 的救济粮。在完成一系列发放任务后,YGH 想知道每一户人家收到的粮食中数量最多的是哪一种。
输入
第一行两个数 n,q,其中 n 表示村庄共有几户人家,q 表示 YGH 一共发放了几次粮食。接下来 n-1 行,每行两个数 x y,表示编号为 x 和 y 的两户人家之间连有边。接下来 q 行,每行三个数 x y w,表示 YGH 选择了 x 到 y 的路径,对每户人家发放 1 袋种类为 w 的粮食。
输出
输出 n 行,第 i 行输出编号为 i 的人家收到的粮食中数量最多的种类号,如果有多个数量相同的粮食,输出其中最小的种类号,如果没有收到粮食,输出0
样例输入
[1]
2 4
1 2
1 1 1
1 2 2
2 2 2
2 2 1
[2]
5 3
1 2
3 1
3 4
5 3
2 3 3
1 5 2
3 3 3
样例输出
[1]
1
2
[2]
2
3
3
0
2
提示
对于 40% 的数据 n<=1000,q<=1000,1<=w<=1000
对于 100% 的数据 n<=100000,q<=100000,1<=w<=100000 1<=x,y<=n
原题请见HDU5029 orz
这道题处于习惯,来了个倍增,于是乎超时超时妥妥,还写了130多行orz后来在网上艰难地学习了树链剖分,发现真的很神奇!!!
其实重点不是树链剖分,而是这道题巧妙的处理:
1.将操作先全部叉分在剖分后的链上。
2.从左往右扫描链的时候,用线段树对于颜色(粮食)进行维护,在存点的颜色(粮食)时用链表存,我大概多开了个几倍免得不够用因为不会用vector。扫描的时候只需将颜色update就可以了,复杂度最大大概是q*logn*logm?
代码代码:
#include
#include
#include
#define L(x)(x<<1)
#define R(x)(x<<1|1)
using namespace std;
const int N=1e5+5,M=20000005;
int n,q,x,y,z,ans[N],gx[N];
int head[N],nexxt[N*2],tov[N*2],tot;//树
int head_[N],nexxt_[M],tov_[M],tot2;//颜色
int dp[N],son[N],fa[N],w[N],gen,siz[N],top[N],ad;//树链
struct node{
int l,r,ma,cc;
}cl[N*4];
void build1(int a,int b)
{tot++;nexxt[tot]=head[a];tov[tot]=b;head[a]=tot;}
void build2(int a,int b)
{tot2++;nexxt_[tot2]=head_[a];tov_[tot2]=b;head_[a]=tot2;}
void dfs1(int k)
{
siz[k]=1;son[k]=0;
int u=head[k],v=tov[u];
int ma=0;
while(u)
{
if(v!=fa[k])
{
fa[v]=k;dp[v]=dp[k]+1;
dfs1(v);
siz[k]+=siz[v];
if(siz[v]>ma)son[k]=v,ma=siz[v];
}
u=nexxt[u];v=tov[u];
}
}
void dfs2(int k,int b)
{
w[k]=++ad;top[k]=b;
int u=head[k],v=tov[u];
if(son[k])dfs2(son[k],b); //重
while(u)
{
if(v!=fa[k]&&v!=son[k])
dfs2(v,v); //轻
u=nexxt[u];v=tov[u];
}
}
void pre()
{
for(int i=1;i<=n-1;i++)
{
scanf("%d%d",&x,&y);
build1(x,y);build1(y,x);
}
gen=(1+n)>>1;
dp[gen]=1;fa[gen]=0;
dfs1(gen);
dfs2(gen,gen);
}//预处理树链剖分
void upda(int v)
{
int u=v>>1;
if(cl[R(u)].ma>cl[L(u)].ma)cl[u].ma=cl[R(u)].ma,cl[u].cc=cl[R(u)].cc;
else cl[u].ma=cl[L(u)].ma,cl[u].cc=cl[L(u)].cc;
}
void build_tree(int u,int le,int ri)
{
cl[u].l=le;cl[u].r=ri;
if(le==ri){gx[le]=u;cl[u].cc=le;cl[u].ma=0;return;}
int mid=(le+ri)>>1;
build_tree(L(u),le,mid);
build_tree(R(u),mid+1,ri);
upda(u>>1);
}
void update(int u)
{
if(!u)return;
int mm,ty;
if(cl[R(u)].ma>cl[L(u)].ma)mm=cl[R(u)].ma,ty=cl[R(u)].cc;
else mm=cl[L(u)].ma,ty=cl[L(u)].cc;
if(!mm)ty=0;
if(cl[u].ma!=mm||cl[u].cc!=ty)
{
cl[u].ma=mm;cl[u].cc=ty;
update(u>>1);
}
}
void devi(int a,int b,int c)
{
int f1=top[a],f2=top[b];
while(f1!=f2)
{
if(dp[f1]1,-c);
a=fa[f1];f1=top[a];
}
if(dp[a]>dp[b])swap(a,b);
build2(w[a],c);build2(w[b]+1,-c);
}
void worrk()
{
for(int i=1;i<=q;i++)
{
scanf("%d%d%d",&x,&y,&z);
devi(x,y,z);
}
build_tree(1,1,100000);
for(int i=1;i<=n;i++)
{
int u=head_[i],v=tov_[u];
while(u)
{
int k=1;
if(v<0)k=-1,v=-v;
int hh=gx[v];
cl[hh].ma+=k;
update(hh>>1);
u=nexxt_[u];v=tov_[u];
}
ans[i]=cl[1].cc;
}
for(int i=1;i<=n;i++)
printf("%d\n",ans[w[i]]);
}
int main()
{
freopen("rice.in","r",stdin);
freopen("rice.out","w",stdout);
scanf("%d%d",&n,&q);
pre();
worrk();
return 0;
}