Div2-A
题意:有m个拼图,每个拼图有f[i]块.从中选出n个,使得 (其中块数最大减块数最小的值) 最小.
思路:把f按从小到大的顺序排序,然后顺次尝试.
#include<stdio.h>
int s[55];
int main()
{
int N,M,i,j;
while (scanf("%d%d",&N,&M)!=EOF)
{
for (i=1;i<=M;i++) scanf("%d",&s[i]);
for (i=1;i<=M-1;i++)
for (j=i+1;j<=M;j++)
if (s[i]>s[j])
{
int tmp=s[i];
s[i]=s[j];
s[j]=tmp;
}
int Min=10000;
for (i=1;i+N-1<=M;i++)
if (s[i+N-1]-s[i]<Min) Min=s[i+N-1]-s[i];
printf("%d
",Min);
}
return 0;
}
Div2-B
题意:屏幕尺寸是a:b,视频尺寸是c:d.求出保持该比例的前提下屏幕最少空余多大.
思路:显然a和b中必有一个充满,若b充满,则有dx=b=>x=b/d.从而a方向占用cx=bc/d.总的占用率为bc/ad.类似地,当a充满是占用比例为ad/bc.
注意:若a:b=c:d时应输出0/1,而不是0/20之类的.
#include<stdio.h>
int gcd(int a,int b)
{
if (b==0) return a;
return gcd(b,a%b);
}
int main()
{
int a,b,c,d,p,q;
scanf("%d%d%d%d",&a,&b,&c,&d);
p=a*d;
q=b*c;
if (p>q)
{
int tmp=p;
p=q;
q=tmp;
}
p=q-p;
if (p==0) printf("0/1
");
else
{
int tmp=gcd(p,q);
while (tmp!=1)
{
p/=tmp;
q/=tmp;
tmp=gcd(p,q);
}
printf("%d/%d
",p,q);
}
return 0;
}
Div2-C/Div1-A
题意:有n个问题,答对一个得一分,每连答对k个得分double一次.若答对m个,求最小得分.
思路:显然尽量不要发生double,为此,构造这样一种struct:{连对k-1个,错一个}或{错一个,连对k-1个}.若不得不发生double,则让double发生的越早越好.由于发生double的次数可能非常多,达到1e9次,不能硬算.考虑到一开始得分为0,经过连续几次double(操作为 "+k)*2" )后得分变成如下:2k,6k,14k,30k,62k,126k,可以猜测第i次之后为(2^1+2^2+2^3+......+2^i)k=(2^(i+1)-2)k.使用数学归纳法可以轻易证明这个结论.
#include<stdio.h>
__int64 pow(__int64 n,__int64 M)
{
if (n==0) return 1;
if (n==1) return 2;
__int64 tmp=pow(n/2,M);
if (n&1) return ((tmp*tmp)*2)%M;
else return (tmp*tmp)%M;
}
int main()
{
__int64 N,M,K;
scanf("%I64d%I64d%I64d",&N,&M,&K);
__int64 S1=M/(K-1),S2=N-M;
if (S1<=S2) printf("%I64d
",M);
else
{
__int64 R=M-S2*(K-1),S;
__int64 OP=R/K;
S=((pow(OP+1,1000000009)-2)*K)%1000000009;
S=(S+M-OP*K)%1000000009;
if (S<0) S+=1000000009;
printf("%I64d
",S);
}
return 0;
}
Div2-D/Div1-B
题意:有n个村庄,其中m个被僵尸攻击.已知僵尸会攻击与它距离小于等于d的,求僵尸可能位于哪几个村庄能产生这种现象.
思路beta1(TLE):对于m个村庄,bfs距离小于等于d的点,求m个的交集.
#include<stdio.h>
#include<string.h>
#include<vector>
#include<queue>
using namespace std;
struct node
{
int nx,step;
};
vector<int> G[100010];
int s[100010],aff[100010];
bool inq[100010];
int N,M,D,T;
void bfs(int u)
{
queue<node> q;
int i;
while (!q.empty()) q.pop();
node S;
S.nx=u;
S.step=0;
memset(inq,false,sizeof(inq));
q.push(S);
inq[u]=true;
while (!q.empty())
{
S=q.front();
q.pop();
s[S.nx]++;
if (S.step<D)
{
for (i=0;i<G[S.nx].size();i++)
{
int v=G[S.nx][i];
if (!inq[v])
{
inq[v]=true;
node tmp;
tmp.nx=v;
tmp.step=S.step+1;
q.push(tmp);
}
}
}
}
}
int main()
{
scanf("%d%d%d",&N,&M,&D);
int i,j;
for (i=1;i<=M;i++) scanf("%d",&aff[i]);
for (i=1;i<=N;i++) G[i].clear();
for (i=1;i<N;i++)
{
int u,v;
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
memset(s,0,sizeof(s));
for (i=1;i<=M;i++)
{
bfs(aff[i]);
T=0;
for (j=1;j<=N;j++)
if (s[j]==i) T++;
if (T==0)
{
printf("0
");
return 0;
}
}
T=0;
for (i=1;i<=N;i++)
if (s[i]==M) T++;
printf("%d
",T);
return 0;
}
思路beta2:求出每个点离被僵尸攻击的村庄的最远距离,若小于等于d则ans++,距离分为两部分,一部分向儿子方向找,记为distdown,另一部分向父亲方向找,记为distup.
#include<stdio.h>
#include<string.h>
#include<vector>
#define MAX(X,Y) (X>Y ? X:Y)
using namespace std;
int N,M,D,T;
vector<int> G[100010];
int distup[100010],distdown[100010],father[100010],dd[100010],ff[100010];
bool aff[100010];
void dfsd(int u)
{
int i,Max=-10000000,cur;
dd[u]=-10000000;
for (i=0;i<G[u].size();i++)
{
int v=G[u][i];
if (v==father[u]) continue;
dfsd(v);
if (aff[v]) cur=MAX(distdown[v]+1,1);
else cur=distdown[v]+1;
if (cur>Max)
{
dd[u]=Max;
Max=cur;
ff[u]=v;
}
else dd[u]=MAX(dd[u],cur);
}
distdown[u]=Max;
}
void dfsu(int u)
{
int i,Max=-10000000,f=father[u],cur;
/*for (i=0;i<G[f].size();i++)
{
int v=G[f][i];
if (v==u || v==father[f]) continue;
if (distdown[v]==0)
{
if (aff[v]) Max=Max>2 ? Max:2;
}
else Max=Max>distdown[v]+2 ? Max:distdown[v]+2;
}*/
if (u==ff[f]) Max=dd[f]+1;
else Max=distdown[f]+1;
/*if (distup[f]==0)
{
if (aff[f]) Max=Max>1 ? Max:1;
}
else Max=Max>distup[f]+1? Max:distup[f]+1;*/
if (aff[f]) cur=MAX(distup[f]+1,1);
else cur=distup[f]+1;
Max=MAX(Max,cur);
distup[u]=Max;
for (i=0;i<G[u].size();i++)
{
int v=G[u][i];
if (v==father[u]) continue;
dfsu(v);
}
}
void build(int u)
{
int i;
for (i=0;i<G[u].size();i++)
{
int v=G[u][i];
if (v==father[u]) continue;
father[v]=u;
build(v);
}
}
int main()
{
int i;
scanf("%d%d%d",&N,&M,&D);
memset(aff,false,sizeof(aff));
for (i=1;i<=M;i++)
{
int x;
scanf("%d",&x);
aff[x]=true;
}
for (i=0;i<=N;i++) G[i].clear();
for (i=1;i<N;i++)
{
int u,v;
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
memset(father,0,sizeof(father));
memset(distdown,0,sizeof(distdown));
memset(distup,0,sizeof(distup));
distup[0]=distdown[0]=dd[0]=-10000000;
build(1);
dfsd(1);
dfsu(1);
T=0;
for (i=1;i<=N;i++)
if (distup[i]<=D && distdown[i]<=D) T++;
printf("%d
",T);
return 0;
}
Div2-E/Div1-C
题意:定义因子树:叶节点均为质数,其余节点的值为该节点所有儿子的乘积.要求构造一个节点数最小的因子树,包含给定的几个数字a[i].
思路:显然在a[i]之外的数字只有可能出现在根节点或叶节点上,从而通过枚举a的构造方式求出最小值.
#include <algorithm>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#define N 1000010
#define int64 long long
#define For(i,x,y) for (i=x;i<=y;i++)
using namespace std;
struct ww
{
int64 a;
int sum;
} a[10];
int i,j,k,n,m,an;
int f[N],p[N],sum[N],s[100],ff[10],f1[10];
int64 x,g[N];
inline void prepare()
{
int i,j,k,u;
For(i,2,N-1)
{
if (!f[i]) f[i]=p[++*p]=i;
for (j=1;j<=*p&&p[j]<=f[i]&&p[j]*i<N;j++) f[p[j]*i]=p[j];
}
}
inline bool cc1(const ww &a,const ww &b)
{
return a.sum<b.sum;
}
void dfs(int x,int y,int sum)
{
if (x>n)
{
an=min(an,y+(sum>1));
return;
}
y+=(a[x].sum>1)+a[x].sum-f1[x];
dfs(x+1,y,sum+1);
int i;
For(i,x+1,n)
{
if (a[i].a/g[i]%a[x].a==0)
{
f1[i]+=a[x].sum; g[i]*=a[x].a; dfs(x+1,y,sum); g[i]/=a[x].a;
f1[i]-=a[x].sum;
}
}
}
int main()
{
scanf("%d",&n);
For(i,1,n) scanf("%I64d",&a[i].a);
prepare();
For(i,1,n)
{
for (j=1,x=a[i].a;j<=*p&&x>1;j++)
for (;x%p[j]==0;x/=p[j],a[i].sum++);
if (x>1) a[i].sum++; g[i]=1;
}
sort(a+1,a+n+1,cc1);
an=N; dfs(1,0,0);
printf("%d
",an);
return 0;
}