The 12th Zhejiang University Programming Contest 第十二届浙大校赛题,在zoj上是:3591-3599
这套题可以说是比较难的,真想做7个!!!但是,遗憾的是,这套题真的很难!即使看着集体报告做,我也没做到7个题,而且还有好几个不明白怎么证明,真心给做出来的人跪了。囧……
同样,给一个解题报告网址:http://blog.sina.com.cn/s/blog_5123df350100zk1d.html
zoj 3591 Nim 这个就是nim的变形,列出给定的a数组,b[i]为前i个数的异或值,则看b[i]中不相同两个数构成的对的个数就是了,当然还要加上单个不为零的情况。
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
int a[100010], b[100010];
void deal(int N ,int S,int W)
{
int g = S;
for (int i=0; i<N; i++) {
a[i] = g;
if( a[i] == 0 ) { a[i] = g = W; }
if( g%2 == 0 ) { g = (g>>1); }
else { g = (g>>1) ^ W; }
if(i != 0) a[i] = a[i]^a[i-1];
}
}
int main()
{
int t;
cin >> t;
int n,s,w;
while(t--)
{
cin >> n >> s >> w;
deal(n,s,w);
memset(b,0,sizeof(0));
sort(a,a+n);
int kk = 1;
b[0] = 1;
for(int i = 1;i < n;i++)
{
if(a[i] != a[i-1])
{
b[kk] = 1;a[kk++] = a[i];
}
else b[kk-1]++;
}
long long re = 0;
//for(int i = 0;i < kk;i++) cout << a[i] << " " << b[i] << "\n";
for(int i = 0;i < kk;i++)
re += (long long)(n - b[i]) * b[i];
re = re/2;
re += n;
if(a[0] == 0) re -= b[0];
cout << re << "\n";
}
return 0;
}
zoj 3592 Flipping the Board 整套题中最难得一个,不会!
zoj 3593 One Person Game 数学题
这个中的A,B太大了,不可能是搜索之类的,只能是数学了,当然是gcd,扩展欧几里得之类的,求出来通解容易,再准确的给出结果却是不简单的,这类题,我最愁的也就是给出结果的部分,
求出通解公式fx,fy之后,当fx,fy异号的时候re= abs(fx)+abs(fy) 当两个同号的时候 re = min(abs(fx),abs(fy));
其实通解是fx=x0+b0t;fy=y0-a0t; 这儿的t 的取值是很有讲究的,大约在fx=0或者fy=0或者fx=fy这三种情况 分别判断就是了
这个是我看了别人的题解之后我才想明白,囧
#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b)
{
if(b==0)return a;
else return gcd(b,a%b);
}
ll ext_gcd(ll a,ll b,ll& x,ll& y)
{
ll t,ret;
if (!b)
{
x=1,y=0;
return a;
}
ret=ext_gcd(b,a%b,x,y);
t=x,x=y,y=t-a/b*y;
return ret;
}
ll get(ll &re,ll xx,ll yy)
{
if(xx*yy>=0)re=min(re,max(abs(xx),abs(yy)));
else re=min(re,abs(xx)+abs(yy));
return re;
}
ll deal(ll &re,ll x,ll y,ll addx,ll addy)
{
get(re,x,y);
get(re,x+addx,y-addy);
get(re,x-addx,y+addy);
return re;
}
ll get_step(ll x,ll y,ll addx,ll addy)
{
ll r = (long long)0x7fffffff*10000000,k,kx,ky;
k=(y-x)/(addx+addy);
deal(r,x+k*addx,y-k*addy,addx,addy);
kx=x/addx;
ky=y/addy;
deal(r,x+kx*addx,y-kx*addy,addx,addy);
deal(r,x+ky*addx,y-ky*addy,addx,addy);
return r;
}
int main()
{
ll A,B,a,b,t,d,x,y;
cin>>t;
while(t--)
{
cin>>A>>B>>a>>b;
A=B-A;
if(!A)printf("0\n");
else
{
d=gcd(a,b);
if(A%d) printf("-1\n");
else
{
A/=d;
a/=d;
b/=d;
ext_gcd(a,b,x,y);
x=x*A;
y=y*A;
cout<<get_step(x,y,b,a)<<endl;
}
}
}
return 0;
}
zoj 3594 给出公元多少年,给出甲子表示,题目挺简单,但是有一个坑,公元纪年没有公元0年直说,公元前1年之后是公元1年!!!!长知识了!
zoj 3595 Two Sequences 高数题,真心的跪了,大一学的东西全部忘干净了,什么无穷级数,什么微分方程,什么求导数,而且有比较复杂的公式变换,囧,就这样吧,结果很简单
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
double a0,x;
int N;
int main()
{
while(scanf("%lf",&a0)!=EOF)
{
scanf("%d",&N);
double s=0.0;
for(int i=0;i<N;i++)
{
scanf("%lf",&x);
s+=x*x/2.0+x;
}s/=(double)N;
printf("%.8f\n",a0*exp(s));
}
return 0;
}
zoj 3596 Digit Number 这个题也是比较难得,但是看解题报告这个是广搜,记忆化的广搜,奇了!!看懂了思路,但是思路还是很模糊,这个都能想出来,看来我的水平还得继续提升啊!!
zoj 3597 Hit the Target! 线段树!!!
线段树可以说做的也不少了,这个难度的还真是不多!可以说这个题的模型难建!现在才知道,自己和大神的差距是多大了,是不是这样的题大神们可以秒杀呢??
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define N 50010
//Ï߶ÎÊ÷/
int lazy[N*4],num[N*4];
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
void PushUp(int rt)
{
num[rt] = max(num[rt<<1],num[rt<<1|1]);
}
void PushDown(int rt,int m)
{
if(lazy[rt])
{
lazy[rt<<1] += lazy[rt];
lazy[rt<<1|1] += lazy[rt];
num[rt<<1] += lazy[rt];
num[rt<<1|1] += lazy[rt];
lazy[rt] = 0;
}
}
void init(int n)
{
for(int i = 0;i <= n*4+1;i++)
{
lazy[i] = 0;
num[i] = 0;
}
}
void update(int L,int R,int c,int l,int r,int rt)
{
if(R - L < 0) return;
if(L <= l && r <= R)
{
lazy[rt] += c;
num[rt] += c;
return;
}
PushDown(rt,r-l+1);
int m = (l+r)>>1;
if(L <= m) update(L,R,c,lson);
if(m < R) update(L,R,c,rson);
PushUp(rt);
}
//
int shot[N];
#define M 100010
struct note
{
int a,b;
}data[M];
bool cmp(const note a,const note b)
{
return a.a < b.a || (a.a == b.a && a.b < b.b);
}
int n,m,p,q,k;
void deal(int i,int c)
{
if(shot[i])
{
int t = shot[i];
int pre = data[t].b-1;
do
{
update(max(pre+1,data[t].b),min(m,data[t].b+q-1),c,1,m,1);
pre = data[t].b+q-1;
t++;
}while(t <= k && data[t].a == data[t-1].a);
}
}
int main()
{
int t;
cin >> t;
while(t--)
{
scanf("%d%d%d%d",&n,&m,&p,&q);
scanf("%d",&k);
memset(shot,0,sizeof(shot));
for(int i = 1;i <= k;i++) scanf("%d%d",&data[i].a,&data[i].b);
if(k == 0) {cout << "0.00\n";continue;}
sort(data+1,data+k+1,cmp);
shot[data[1].a] = 1;
for(int i = 2;i <= k;i++)
if(data[i].a != data[i-1].a) shot[data[i].a] = i;
init(m);//
for(int i = 1;i <= p;i++) deal(i,1);
int now = p;
double re = 0;
while(1)
{
re += num[1];
now++;if(now > n) break;
deal(now,1);
deal(now-p,-1);
}
printf("%.2f\n",re / (n-p+1));
}
return 0;
}
zoj 3598
Spherical Triangle 计算几何,跳过,自己不会!
zoj 3599 Game 博弈,这一套题中居然有两个博弈!!!真心不知道出题者怎么想的。
但是这个题的博弈真心的很难!!!!现在只知道结论,但是不知道为什么!!给了一个英文的网址,可是真心的看不懂
/*
zju比赛时被gao了,半天找不到好的规律,特在次几下这一类的博弈问题通解。
一个石子堆,先手不能全部取玩,每次取石子数在[1,f(前一次取的石子数)],f(x) >= x;
H(1) = 1,H(k+1) = H(k) + H(m),m = min{ j | f( H(j) ) >= H(k)}。
该数列为所有必败局面。
目前只知其然,不知其所以然。
*/
#include <iostream>
using namespace std;
long long data[1000000];
long long deal(int m,int n)
{
data[1] = 1;
int pre = 1;
for(int k = 2;;k++)
{
int j;
for(j = pre;j < k;j++) if(data[j]*m >= data[k-1]) break;
pre = j;
data[k] = data[k-1]+data[j];
cout << data[k] << " " ;
//cout << n << " " << k << " \n " ;
if(data[k] > n) return n-k+1;
}
return 0;
}
int main()
{
int t;
cin >> t;
while(t--)
{
int m,n;
cin >> m >> n;
cout << deal(m,n) << "\n";
}
return 0;
}