您的位置:首页 > 其它

牛客练习赛17

2018-05-05 16:40 204 查看

 

 A. 链接:https://www.nowcoder.com/acm/contest/109/A
来源:牛客网

题目描述

给出共享长方体一个顶点的三个面的面积,求它十二条边的边长和。

输入描述:

一行三个整数a, b, c表示面积(1 <= a, b, c <= 10000)。

输出描述:

一行一个整数表示边长和。
示例1

输入

1 1 1

输出

12
示例2

输入

4 6 6

输出

28

设三边长度为A,B,C,则有a=AB,b=BC,c=AC,枚举一下B如果满足B是a和b的因子且能满足c=AC,就直接计算输出结果。     
#include<iostream>
#include<cstring>
#include<queue>
#include<cstdio>
#include<stack>
#include<set>
#include<map>
#include<cmath>
#include<ctime>
#include<time.h>
#include<algorithm>
using namespace std;
#define mp make_pair
#define pb push_back
#define debug puts("debug")
#define LL long long
#define pii pair<int,int>
#define eps 1e-10
int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
int main()
{
int n,m,i,j,k;
LL a,b,c;
LL A,B,C;
cin>>a>>b>>c;
n=max(a,b);
for(B=1;B<=n;++B){
if(a%B==0&&b%B==0){
if(c==a/B*b/B){
cout<<4*(B+a/B+b/B)<<endl;
return 0;
}
}
}
return 0;
}

 



B. 链接:https://www.nowcoder.com/acm/contest/109/B
来源:牛客网

题目描述

给出两个串s和x
定义s中的某一位i为好的位置,当且仅当存在s的子序列 满足y=x且存在j使得i=kj成立。
问s中是否所有的位置都是好的位置。

输入描述:

一行两个字符串s,x,这两个串均由小写字母构成。
1 <= |s|, |x| <= 200000

输出描述:

Yes表示是。
No表示不是。
示例1

输入

abab
ab

输出

Yes
示例2

输入

abacaba
aba

输出

No
示例3

输入

abc
ba

输出

No

kmp跑一波遇见怎么也无法匹配的点就输出no即可。     
#include<iostream>
#include<cstring>
#include<queue>
#include<cstdio>
#include<stack>
#include<set>
#include<map>
#include<cmath>
#include<ctime>
#include<time.h>
#include<algorithm>
using namespace std;
#define mp make_pair
#define pb push_back
#define debug puts("debug")
#define LL long long
#define pii pair<int,int>
#define eps 1e-10
LL R=6371009;
int f[202020];
int g[202020];
char s[202020];
char x[202020];
int main()
{
int n,m,i,j,k;
double x1,y1,x2,y2;
scanf("%s%s",s,x);
int n1=strlen(s);
int n2=strlen(x);
f[0]=-1;
for(i=1;i<=n2;++i){
j=f[i-1];
while(j!=-1&&x[i-1]!=x[j]) j=f[j];
f[i]=j+1;
}
for(i=0,j=0;i<n1;++i){
if(s[i]==x[j]){
j++;
}
else{
while(j!=-1&&x[j]!=s[i]) j=f[j];
j++;
}
if(j==n2){
g[i]=n2;
j=f[j];
//    j++;
}
}
int l=n1;
bool ok=1;
//    for(i=0;i<n1;++i)
//    cout<<"gi="<<g[i]<<endl;
for(i=n1-1;i>=0;--i){
if(g[i]==0&&l>=i){
ok=0;
break;
}
if(g[i]){
l=i-n2;
}
}
ok?puts("Yes"):puts("No");
return 0;
}

/*
ababbab
ab
*/

 



C.
链接:https://www.nowcoder.com/acm/contest/109/C
来源:牛客网

题目描述

给定长度为n的数组a,定义一次操作为:
1. 算出长度为n的数组s,使得si= (a[1] + a[2] + ... + a[i]) mod 1,000,000,007;
2. 执行a = s;
现在问k次操作以后a长什么样。

输入描述:

第一行两个整数n,k(1 <= n <= 2000, 0 <= k <= 1,000,000,000);
第二行n个整数表示a数组(0 <= a
i
<= 1,000,000,000)。

输出描述:

一行n个整数表示答案。
示例1

输入

3 1
1 2 3

输出

1 3 6
示例2

输入

5 0
3 14 15 92 6

输出

3 14 15 92 6

    首先注意到这个操作可以用矩阵来表示,设原数组为一个行向量A,k次操作之后得到的行向量B, 转移矩阵为X,则有A*Xk=B ,观察发现X是一个N*N的上三角矩阵,

  可即使使用了快速幂,这个矩阵一次乘法的时间复杂度也不允许接受,因为N<=2000,N^3过于庞大,枚举了这个矩阵的前几次方之后发现一个规律,这个矩阵只要知道
第一行的元素就可以推出这个全部的矩阵,每一列都来自于第一行的一个子段,再观察发现这些数字都是杨辉三角里的数,准确的说这一行数对应杨辉三角的一列(斜着),
对于X^k,这个矩阵,第一行的元素就是( C(k-1,0) , C(k,1) , C(k+1,2),.....C(k+n-2,n-1)),组合数的公式C(n,r)=C(n,r-1)*(n-r+1)/r,
C(n,r)=C(n-1,r)+C(n-1,r-1),联立得出C(n,r)=C(n-1,r-1)*n/r,有除法记得取逆元。
  
#include<iostream>
#include<cstring>
#include<queue>
#include<cstdio>
#include<stack>
#include<set>
#include<map>
#include<cmath>
#include<ctime>
#include<time.h>
#include<algorithm>
using namespace std;
#define mp make_pair
#define pb push_back
#define debug puts("debug")
#define LL long long
#define pii pair<int,int>
#define eps 1e-10
double R=6371009;

LL MOD=1e9+7;
LL q[2020];
LL a[2020];
void gcd(LL a,LL b,LL &d,LL &x,LL &y)
{
if(!b) {d=a;x=1;y=0;}
else {gcd(b,a%b,d,y,x);y-=x*(a/b);}
}
LL inv(LL a,LL n)
{
LL d,x,y;
gcd(a,n,d,x,y);
return d==1?(x+n)%n:-1;
}
int main()
{
LL n,m,i,j,k;
scanf("%lld%lld",&n,&k);
for(i=1;i<=n;++i) scanf("%lld",a+i);
k--;
q[1]=1;
for(i=2;i<=n;++i){
q[i]=q[i-1]*((k+i-1)%MOD)%MOD*inv(i-1,MOD);
q[i]%=MOD;
}
//for(i=2;i<=n;++i) q[i]+=q[i-1],q[i]%=MOD;
for(i=1;i<=n;++i){
LL tmp=0;
for(j=1;j<=i;++j){
tmp+=a[j]*q[i-j+1];
tmp%=MOD;
}
printf("%lld%c",tmp,i==n?'\n':' ');
}
return 0;
}

 

 E.
链接:https://www.nowcoder.com/acm/contest/109/E
来源:牛客网

题目描述



给定一幅n个点m条边的图和S个一定要经过的点,问从0号点出发,经过这S个点再回到0号点的最短路径长度是多少。

输入描述:

第一行一个整数T(T <= 2)表示数据组数。
对于每组数据,第一行两个整数n,m表示点数和边数(1 <= n, m <= 100,000)。
接下来m行,每行三个整数x, y, z(0 < x, y < n, 0 <= z <= 1000)表示xy之间有一条长度为c的双向边;
接下来一个整数S。(S<=10)
接下来S行每行一个整数表示一定要经过的点。
数据保证有解。

输出描述:

T行,每行一个整数表示答案。
示例1

输入

1
4 6
0 1 1
1 2 1
2 3 1
3 0 1
0 2 5
1 3 5
3
1
2
3

输出

4

    全卡在C没来得及看这个其实不难,跑S+1(0和必经的S个点)次最短路,将点离散化然后dp,f[S][i]表示当前走的点的集合S且最后一个经过的点为i点的最短路径,
最后枚举全集加上dis(0,i)即可。优先队列忘记重载比较算子神特么过了样例结果一直WA,还有前向星蜜汁写错,可能老了= =
    
#include<iostream>
#include<cstring>
#include<queue>
#include<cstdio>
#include<stack>
#include<set>
#include<map>
#include<cmath>
#include<ctime>
#include<time.h>
#include<algorithm>
using namespace std;
#define mp make_pair
#define pb push_back
#define debug puts("debug")
#define LL long long
#define pii pair<int,int>
#define eps 1e-10
#define inf 0x3f3f3f3f
struct Edge{
int v,w,next;
}e[202020];
int first[101010],tot;
void add(int u,int v,int w){
e[tot].v=v;
e[tot].w=w;
e[tot].next=first[u];
first[u]=tot++;
}
int f[(1<<12)][12];
int d[12][101010];
bool vis[101010];
int x[15];
int N,M,S;
void dij(int s,int ps){
memset(vis,0,sizeof(vis));
d[ps][s]=0;
priority_queue<pii,vector<pii>,greater<pii> >q;
q.push(mp(0,s));
while(!q.empty()){
int u=q.top().second;
q.pop();
if(vis[u]) continue;
vis[u]=1;
for(int i=first[u];i!=-1;i=e[i].next){
int v=e[i].v,w=e[i].w;
if(d[ps][v]>d[ps][u]+w){
d[ps][v]=d[ps][u]+w;
q.push(mp(d[ps][v],v));
}
}
}
}

int main()
{
int t,i,j,k;
scanf("%d",&t);
while(t--){
memset(d,inf,sizeof(d));
memset(first,-1,sizeof(first));
tot=0;
int u,v,w;
scanf("%d%d",&N,&M);
while(M--){
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
add(v,u,w);
}

scanf("%d",&S);
dij(0,0);
x[0]=0;
for(i=1;i<=S;++i){
scanf("%d",&u);
x[i]=u;
dij(u,i);
}
memset(f,inf,sizeof(f));
f[1][0]=0;
for(int s=0;s<=(1<<(S+1));s++){
for(j=0;j<=S;++j){
if(f[s][j]!=inf){
for(int k=0;k<=S;++k){
if((s&(1<<k))==0&&d[j][x[k]]!=inf){
f[s|(1<<k)][k]=min(f[s|(1<<k)][k],f[s][j]+d[j][x[k]]);
}
}
}
}
}

int ans=inf;
int all=(1<<(S+1))-1;
for(i=0;i<=S;++i)
ans=min(ans,f[all][i]+d[0][x[i]]);
cout<<ans<<endl;
}
return 0;
}

 



 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: