[JSOI2008]球形空间产生器sphere 【高斯消元】

【题目链接】http://61.187.179.132:8080/JudgeOnline/showproblem?problem_id=1013
【题目大意】
求高维球心坐标。
【算法分析】
首先距离公式容易推知,然后点到球心距离必然都相等,于是联立n条等式,高斯消元即可。
另外:
我爬山法好像陷进局部最优解里去了,我爬山用的是方差作估价函数,直接WA。
估计最后一名的800+MS的神牛就是爬山过的。求爬山正确的估价函数。
【其它】高斯消元1Y。
【CODE】
#include #include #include #include #define sqr(x) ((x)*(x))
const int N=15;
int n;
double a[N][N],c[N][N];

void Swap(int x,int y){
double tmp;
for (int i=0;i<=n;i++){
tmp=c[x][i];
c[x][i]=c[y][i];
c[y][i]=tmp;
}
}

void guass(){
int i,j,k;
for (i=1;i<=n;i++){
for (k=i,j=i;j<=n;j++)
if (fabs(c[j][i-1])>fabs(c[k][i-1])) k=j;
Swap(i,k);
for (j=i+1;j<=n;j++)
for (k=n;k>=i-1;k–)
c[j][k]-=c[i][k]*c[j][i-1]/c[i][i-1];
}
}

void solve(){
double ans[N];
memset(ans,0,sizeof(ans));
ans[n]=1;
for (int i=n;i>=1;i–){
double Sum=0;
for (int j=i;j<=n;j++)
Sum-=ans[j]*c[i][j];
ans[i-1]=Sum/c[i][i-1];
}
for (int i=0;i if (i) printf(" ");
printf("%.3lf",ans[i]);
}
printf("n");
}

int main(){
scanf("%d",&n);
for (int i=0;i<=n;i++)
for (int j=0;j scanf("%lf",&a[i][j]);
memset(c,0,sizeof(c));
for (int i=1;i<=n;i++){
for (int j=0;j c[i][j]=2*(a[i][j]-a[i-1][j]);
c[i][n]+=sqr(a[i-1][j])-sqr(a[i][j]);
}
}
guass();
solve();
}

[JSOI2008]最大数maxnumber 【线段树】

【题目链接】http://61.187.179.132:8080/JudgeOnline/showproblem?problem_id=1012
【算法分析】
线段树,会的人都知道。。。
【其它】1Y。用cin果断跑到几乎最慢
【做题原因】邻近省选,练练手,刷出1Y,刷出自信。
【CODE】
#include #include #include #include using namespace std;
const int INF=0x7FFFFFFF;
struct Node{int l,r,key;}Tr[1000000];
int m,mod,n,ans;

void build(int p,int l,int r){
Tr[p].l=l; Tr[p].r=r; Tr[p].key=-INF;
if (l int mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
}
}

void Add(int p,int t,int key){
if (Tr[p].l==Tr[p].r){
Tr[p].key=key;
return;
}
if (t<=(Tr[p].l+Tr[p].r)/2) Add(p*2,t,key);
else Add(p*2+1,t,key);
Tr[p].key=max(Tr[p*2].key,Tr[p*2+1].key);
}

void Get(int p,int l,int r){
if (l<=Tr[p].l && Tr[p].r<=r){
ans=max(ans,Tr[p].key);
return;
}
int mid=(Tr[p].l+Tr[p].r)/2;
if (l<=mid) Get(p*2,l,r);
if (r> mid) Get(p*2+1,l,r);
}

int main(){
ios::sync_with_stdio(false);
ans=n=0;
cin >> m >> mod;
build(1,1,m);
for (int i=1;i<=m;i++){
char ch; __int64 x;
cin >> ch >> x;
if (ch==’A’){
x=(x+ans)%mod;
n++;
Add(1,n,(int)(x));
}
else{
ans=-INF;
Get(1,n-x+1,n);
cout << ans << "n";
}
}
}

[HDOJ3335 Divisibility]【DAG图的最大独立集】【最大反链】【最小链划分】【最小路径覆盖】

【题目大意】
给定N个数,让你取最多的数,使得取出的数里,不存在A是B的倍数这种情况。
【算法分析】
虽然当时ACM_DIY群赛时蒙对了算法,当时推理方式见(那叫一个强力):
http://hi.baidu.com/edwardmj/blog/item/1ae99b3f5f5cbee53d6d9789.html
但一直没有理解,于是今天重温二分图时回来做了一下。
本题可以先把相同的数去掉,然后若A为B的倍数,那么B->A。
由于A>B,那么是一个DAG图(有向无环图)
然后DAG图的最大反链就可以利用匹配来搞。(传递闭包后的DAG图的最大独立集=最大反链)
具体做法是每个点拆两个点,弄成二分图,然后匹配。最后输出n-匹配数。
二分图总结见:http://hi.baidu.com/edwardmj/blog/item/b5fc0419bd3661f1af513325.html
小菜总结,不足谢谢补充。
【CODE】
#include #include #include const int N=1005;
typedef __int64 lld;
struct edge{int y;edge *next;}g[1005555],*ls[N];
int n,e,cnt;
int v[N],link[N];
lld a[N];

int cmp(const void *A,const void *B){
lld AA=*((lld*)A),BB=*((lld*)B);
if (AA>BB) return 1;
if (AA return 0;
}

void addedge(int x,int y){
g[++e].y=y; g[e].next=ls[x]; ls[x]=&g[e];
}

void build(){
int tot=0,i,j;
for (i=1;i<=n;i++)
if (!tot || a[i]!=a[tot])
a[++tot]=a[i];
n=tot;
for (i=1;i<=n;i++)
for (j=i+1;j<=n;j++)
if (a[j]%a[i]==0 && a[j]>a[i])
addedge(i,j);
}

bool Find(int p){
for (edge *t=ls[p];t;t=t->next)
if (v[t->y]!=cnt){
v[t->y]=cnt;
int q=link[t->y];
link[t->y]=p;
if (!q || Find(q)) return true;
link[t->y]=q;
}
return false;
}

void solve(){
memset(link,0,sizeof(link));
memset(v,0,sizeof(v));
int ans=0;
for (cnt=1;cnt<=n;cnt++)
if (Find(cnt)) ans++;
printf("%dn",n-ans);
}

int main(){
int Tc;
scanf("%d",&Tc);
for (;Tc;Tc–){
scanf("%d",&n);
e=0;
for (int i=1;i<=n;i++){
scanf("%I64d",&a[i]);
ls[i]=NULL;
}
qsort(a+1,n,sizeof(lld),cmp);
build();
solve();
}
}

[衡阳八中1457 棋盘游戏]【博弈】【SG函数】【NIM和】【任意一子游戏到达终态结束的游戏】

【题目链接】http://61.187.179.132:8080/JudgeOnline/showproblem?problem_id=1457
【算法分析】
首先,n个皇后是独立的,于是我们联想到利用SG函数来求解。
但是它与传统NIM游戏又有所不同,它是任意一个子游戏到达终态,那么就结束游戏。
好的,现在两个家伙都是绝顶聪明的。
于是他们肯定不会主动去走这样的一步:走完以后,该皇后x==0 || y==0 || x==y。
因为走完这步以后,对方就赢了,我们定义这种行为为沙茶。
因为他们都不会主动沙茶,那么就只能被沙茶。
也就是说所有的皇后的下一步都是令他沙茶的,那么才会真沙茶。
于是我们可以定义,下一步只能做沙茶的点为终态。
那么如果所有子游戏都到达终态,这时候先手必败。
这又刚好与传统NIM游戏一样了~
于是我们只要在计算SG函数时忽略x==0 || y==0 || x==y的点,那么就可以得我们定义所对应的SG函数值。
然后再利用那个Sprague-Grundy Theorem,再加上暴力计算SG函数,顺利解决本题。
【其它】1WA。注意那个SG函数的值好像是可能超100的= =。。。改大了瞬间AC。
【CODE】
#include #include #include #define flag(x,y) (!(!(x) || !(y) || (x)==(y)))
int SG[100][100];
bool v[100][100][205];

void Cal_SG(){
int i,j,k;
for (i=1;i<100;i++)
for (j=1;j<100;j++)
if (flag(i,j)){
for (k=1;i>=k || j>=k;k++){
if (i>=k && flag(i-k,j)) v[i][j][SG[i-k][j]]=true;
if (j>=k && flag(i,j-k)) v[i][j][SG[i][j-k]]=true;
if (i>=k && j>=k && flag(i-k,j-k))
v[i][j][SG[i-k][j-k]]=true;
}
for (k=0;k<=200;k++)
if (!v[i][j][k]){
SG[i][j]=k;
break;
}
}
}

inline void output(int x){
if (!x) puts("T_T");
else puts("^o^");
}

int main(){
int Tc,n,i,x,y,ans,check;
Cal_SG();
scanf("%d",&Tc);
for (;Tc;Tc–){
scanf("%d",&n);
ans=check=0;
for (i=1;i<=n;i++){
scanf("%d%d",&x,&y);
if (!x && !y) check=2;
if (!flag(x,y) && !check) check=1;
ans^=SG[x][y];
}
switch (check){
case 0:output(ans); break;
case 1:output(1); break;
case 2:output(0); break;
}
}
}

[HDOJ2855 Fibonacci Check-up]【找规律~】【矩阵乘法】

【题目大意】
% m
【算法分析】
首先我们发现答案是指关于n的一个函数。
那么我们把小数据暴力一下,得到下表:
0 0 0
1 1 1
2 3 2
3 8 5
4 21 13
5 55 34
6 144 89
7 377 233
8 987 610
9 2584 1597
10 6765 4181
11 17711 10946
12 46368 28657
13 121393 75025
14 317811 196418
15 832040 514229
16 2178309 1346269
17 5702887 3524578
18 14930352 9227465
19 39088169 24157817
20 102334155 63245986
21 267914296 165580141
22 701408733 433494437
23 1836311903 1134903170
24 4807526976 2971215073
25 12586269025 7778742049
26 32951280099 20365011074
27 86267571272 53316291173
28 225851433717 139583862445
29 591286729879 365435296162
30 1548008755920 956722026041
其中第一个是序号,第二个是答案,第三个是ans[i]-ans[i-1]。
设第三个是p[i],那么容易发现p[i]=3*p[i-1]-p[i-2]。
然后列出矩阵求解即可。
【其它】
居然WA了好多遍。。。真不可饶恕啊= =。
WA的原因是:n=0时没有答案输出来。。。。
【CODE】
#include #include #include #include using namespace std;
typedef __int64 lld;
lld n,mod;
lld a[1][3];
lld c[3][3],p[3][3],res[3][3];

void Pow(lld cf){
if (cf==1){
memcpy(p,c,sizeof(c));
return;
}
lld i,j,k;
Pow(cf/2);
memset(res,0,sizeof(res));
for (i=0;i<3;i++)
for (j=0;j<3;j++)
for (k=0;k<3;k++)
res[i][j]=(res[i][j]+p[i][k]*p[k][j])%mod;
memcpy(p,res,sizeof(res));
if (cf%2){
memset(res,0,sizeof(res));
for (i=0;i<3;i++)
for (j=0;j<3;j++)
for (k=0;k<3;k++)
res[i][j]=(res[i][j]+p[i][k]*c[k][j])%mod;
memcpy(p,res,sizeof(res));
}
}

void solve(){
a[0][0]=1; a[0][1]=1; a[0][2]=2;
c[0][0]=1; c[0][1]=0; c[0][2]=0;
c[1][0]=0; c[1][1]=0; c[1][2]=-1;
c[2][0]=1; c[2][1]=1; c[2][2]=3;
Pow(n-1);
lld i,j,k;
memset(res,0,sizeof(res));
for (i=0;i<1;i++)
for (j=0;j<3;j++)
for (k=0;k<3;k++)
res[i][j]=((res[i][j]+a[i][k]*p[k][j])%mod+mod)%mod;
cout << (res[0][0]+mod)%mod << "n";
}

int main(){
lld Tc;
cin >> Tc;
for (lld i=0;i cin >> n >> mod;
if (n==0) cout << "0n";
if (n==1) cout << 1%mod << "n";
if (n>=2) solve();
}
}