9.15上课日记

part1

逆序对
详见代码
顺带归并排序一起复习

#include<bits/stdc++.h>
using namespace std;
int a[100001],b[100001];
long long ans=0;
void lala(int l,int m,int r){
	int i=l,k=l,j=m+1;//i左区间,j右区间 
	while(i<=m&&j<=r){
		if(a[i]>a[j]){//左大于右(逆序了)下来一个右区间
			b[k]=a[j];k++,j++;
			ans+=m-i+1;
		}
		else b[k++]=a[i++];//下来一个左区间(没有逆序) 
	}
	while(i<=m)b[k++]=a[i++];//对于剩余部分直接加入 
	while(j<=r)b[k++]=a[j++];
	for(int i=l;i<=r;i++){//重排
		a[i]=b[i];
	}
}
void guibing(int l,int r){
	if(l<r){
		int m=l+r>>1;
		guibing(l,m);
		guibing(m+1,r);
		lala(l,m,r);
	}
}
int main(){
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	guibing(1,n);
	cout<<ans;
	return 0;
}

然后,我按照题解写了个树状数组

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int a[1000101],b[1000101],c[1000101];
int n;
bool cmp(int x,int y){
	return b[x]>b[y];
}
void add(int x,int cc){
	for(;x<n;x+=(x&(-x)))
		c[x]+=cc;
}
int query(int x){
	int ans=0;
	for(;x>0;x-=(x&(-x)))
		ans+=c[x];
	return ans;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&b[i]);
		a[i]=i;
	}
	sort(a+1,a+n+1,cmp);
	int anss=0;
	for(int i=1;i<=n;i++){
		add(a[i],1);
		anss+=query(a[i]-1);
	}
	cout<<anss;
} 

挂的妈都不认识....
输出和正确答案一毛一样
算了,再说

part 2

搜索优化
预告
n皇后与魔板
对于n皇后,这次选择的是带状压的n<=14的版本
顺手练练状压了
先放个基础n皇后

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int h[100][100]={0},l[100][100]={0},d1[100]={0},d2[100]={0};
int a[100]={0},b[100]={0};
int ans=0,n;
void  dfs(int x){
	if(x==n+1){
//		if(ans<=2){
//			for(int i=1;i<=n;i++)cout<<b[i]<<' ';
//		cout<<endl;
//		}
		ans++;return ;
	}
	for(int i=1;i<=n;i++){
		if(h[x][i]==0&&l[x][i]==0&&d1[x+i]==0&&d2[x-i+n]==0){
			b[x]=i;for(int j=1;j<=n;j++)l[j][i]=1;
			d1[x+i]=1;d2[x-i+n]=1;//cout<<i<<endl;
			dfs(x+1);
			b[x]=0;for(int j=1;j<=n;j++)if(h[j][i]==0)l[j][i]=0;
			l[x][i]=0;d1[x+i]=0;d2[x-i+n]=0;
		}
	}
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++){
			char c;
			cin>>c;
			if(c=='.')h[i][j]=1;
		}
	dfs(1);
	cout<<ans;
	return 0;
}

这是个60分代码
那么这个n=14看来是真的坑了
我仔细看了看位运算,觉得当年的lower老是写挂是有道理的
可惜今天恐怕调不出来了,明天继续;
先转载一篇题解
原链接

#include<bits/stdc++.h>
using namespace std;//用位运算优化
int n,mans,p;
int mark[100],bin[1<<20];
void dfs(int x/*行*/,int a,int b,int c){//列,左上角,右上角标记 
    if(x>n){
        ans++;
        if(ans>=1&&ans<=3){
            for(int i=1;i<=n;i++)printf("%d ",mark[i]+1);//输出标记了的列 
            puts("");
        }
        return;
    }
    int t=(a|b|c)^p;//p记录棋盘下标范围,t判断是否在棋盘内
    while(t) {
        int i=t&(-t);//二进制找到最后一个的全值 
        mark[x]=bin[i];//选择当前棋子 
        dfs(x+1,a|i,(b|i)>>1,((c|i)<<1)&p);//对当前棋子做标记,继续查找 
//a|i记录当前列不能走,b|i表示左上角,(c|i)<<1)&p查找右上角与当前列的重合 
        t-=i;
    }
}
int main(){
    scanf("%d",&n);
    p=(1<<n)-1;//用二进制表示下标范围;
    bin[0]=1;
    for(int i=1; i<=n; i++)bin[1<<i]=i;//二进制标记归位 
    dfs(1,0,0,0);
    printf("%d",ans);
    return 0;
}
posted @ 2018-09-15 18:46  lisuier  阅读(103)  评论(0编辑  收藏  举报