NOIP 2017 模拟
2017 10 8
T1 :
题目:
——正解思路:
将乘法问题转化为log相加问题,比较大小即可。
——我的乱搞:
变成除法问题,并剪枝,最后竟然Ac了。。。。
tips:
生命不息,数学不止。。。。
#include<cstdio>
int n,m,t,fa,fb,mini;
bool az,bz,fan;
float zj,a[100001],b[100001];
inline int read()
{
int i=0;
float f=1.0;
char c=getchar();
while((c<'0'||c>'9')&&c!='-') c=getchar();
if(c=='-') f=-1.0,c=getchar();
while(c>='0'&&c<='9') i=(i<<3)+(i<<1)+c-48,c=getchar();
return i*f;
}
int main()
{
t=read();
while(t--)
{
n=read();
fa=0,fb=0;
az=false,bz=false,fan=false;
for(int i=1;i<=n;++i)
{
a[i]=read();
if(a[i]==0) az=true;
if(a[i]<0) ++fa,a[i]=-a[i];
}
m=read();
for(int i=1;i<=m;++i)
{
b[i]=read();
if(b[i]==0) bz=true;
if(b[i]<0) ++fb,b[i]=-b[i];
}
if((fa-fb)&1)
{
puts(fa&1 ? "Alice" : "Bob");
continue;
}
else if((fa&1)&&(fb&1)) fan=true;
if(az)
{
puts(!fan ? "Alice" : "Bob");
continue;
}
if(bz)
{
puts(!fan ? "Bob" : "Alice");
continue;
}
mini=n < m ? n : m;
zj=1.0;
for(int i=1;i<=mini;++i) zj*=a[i]/b[i];
if(mini==n)
for(int i=mini+1;i<=m;++i)
{
zj/=b[i];
if(zj<1) break;
}
else
for(int i=mini+1;i<=n;++i)
{
zj*=a[i];
if(zj>1) break;
}
puts( !fan ? zj<1 ? "Alice" : "Bob" : zj>1 ? "Alice" : "Bob");
}
return 0;
}
T2 :
题目 :
——正解思路:
dp , 转移方程为 f [ i ][ j ] = min ( f [ i + 1 ][ j + 1 ] , f [ i + 1 ][ j ] , f [ i ][ j + 1 ] ) + a1 [ i + 1 ] * b2 [ j + 1 ];
——我的乱搞:
我选择狗带。。。
正解:
var
n, m, i, j : longint;
a, b : array [0..2002] of longint;
f : array [0..2002, 0..2002] of longint;
function min (a, b, c : longint) : longint;
begin
if a < b then
if a < c then exit (a)
else if c < b then exit (c)
else exit (b)
else
if b < c then exit (b)
else if c < a then exit (c)
else exit (a);
end;
begin
read (n, m);
for i := 1 to n do read (a[i]);
for i := 1 to m do read (b[i]);
fillchar (f, sizeof (f), 63);
f[n + 1][m + 1] := 0;
for i := n downto 1 do
for j := m downto 1 do
f[i][j] := min (f[i + 1][j], f[i][j + 1], f[i + 1][j + 1]) + (a[i] - 1) * (b[j] - 1);
write (f[1][1]);
end.
T3 :
题目:
——正解思路:
用tarjan求双连通分量,然后答案减去每个双连通分量所可以产生的点的大小 C_size[ i ] ^ 2即可。
——我的乱搞:
双连通分量是什么鬼。。。。。
正解:
#include<stdio.h>
#include<time.h>
#include<algorithm>
using namespace std;
long long v[10001],ans;
int n,cnt;
inline long long read()
{
long long i=0;
char ch;
for(ch=getchar();ch<'0'||ch>'9';ch=getchar());
for(;ch>='0' && ch<='9';ch=getchar())
i=(i<<3)+(i<<1)+ch-'0';
return i;
}
inline long long gcd(long long a,long long b)
{
return !b?a:gcd(b,a%b);
}
inline int find(int n,long long aim)
{
if(v[n]==aim) return n;
int l=0,r=n,mid=(l+r)>>1;
for(;l+1<r;mid=(l+r)>>1)
v[mid]<aim?l=mid:r=mid;
return r;
}
int main()
{
n=read();
long long *a=new long long[n+1];
long long *f=new long long[n+1];
for(int i=1;i<=n;++i) a[i]=read();
srand(time(0));
random_shuffle(a+1,a+1+n);
for(int i=1,p=min(n,4);i<=p;++i)
{
register int num=0;
for(long long j=1;j*j<=a[i];++j)
if(a[i]%j==0)
{
v[++num]=j;
f[num]=0;
if(j*j!=a[i])
{
v[++num]=a[i]/j;
f[num]=0;
}
}
sort(v+1,v+1+num);
for(int j=1;j<=n;++j) ++f[find(num,gcd(a[i],a[j]))];
for(int j=1;j<=num;++j)
{
register long long total=0;
if(v[j]<=ans) continue;
for(int k=j;k<=num;++k)
if(v[k]%v[j]==0) total+=f[k];
if(total*2>=n) ans=max(ans,v[j]);
}
}
int num=0;
char c[13];
while(ans) c[++num]=(ans%10)+48,ans/=10;
while(num) putchar(c[num--]);
delete [] a;
delete [] f;
return 0;
}