All Latin Squares

题目大意

n x n矩阵(n=2->7)

第一行1 2 3 4 5 ..N

每行每列,1-N各出现一次,求总方案数

题解

n最大为7 显然打表

写了个先数值后位置的暴搜

#include <bits/stdc++.h>
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--) using namespace std; const string filename = "latin"; void usefile(){
freopen((filename+".in").c_str(),"r",stdin);
freopen((filename+".out").c_str(),"w",stdout);
} int n;
int v[10][10]; // [row][col] int vis[10][10]; // [val][col] int anscnt =0; void dfs(int val,int row){
if(val > n){
anscnt++;
return ;
}
rep(j,1,n+1){
if(v[row][j] == 0 && !vis[val][j]){
v[row][j] = 1;
vis[val][j] = 1;
if(row+1 < n){
dfs(val,row+1);
}else{
dfs(val+1,1);
}
vis[val][j] = 0;
v[row][j] = 0;
}
}
} int main(){
// usefile();
cin>>n;
rep(i,1,n+1){
v[0][i]=i;
vis[i][i]=1;
}
dfs(1,1);
cout<<anscnt<<endl;
return 0;
}

6能搜出来,7要等好久,考虑改算法

但是数列嘛,当然先上OEIS看看http://oeis.org/search?q=1%2C2%2C24%2C1344%2C1128960&sort=&language=english&go=Search

7的时候答案是12198297600,看来直接暴搜是不太可能

考虑 一个成功的方案, 把它的非首行的两行交换,也是合法的

所以考虑第一列也定为1N,最后乘上(N-1)!

这样计算的次数是16942080

在我i7-7700HQ上跑是

> time echo 7 | ./6.5.1
12198297600 real 0m17.194s
user 0m17.190s
sys 0m0.006s

固定第一列的代码

#include <bits/stdc++.h>
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--) using namespace std; const string filename = "latin"; void usefile(){
freopen((filename+".in").c_str(),"r",stdin);
freopen((filename+".out").c_str(),"w",stdout);
} int n;
int v[10][10]; // [row][col] // [0->n-1][1->n]
int vis[10][10]; // [val][col] long long anscnt =0; void dfs(int val,int row){
if(val > n){
anscnt++;
return ;
}
if(val == row+1){
if(row+1 < n){
dfs(val,row+1);
}else{
dfs(val+1,1);
}
return ;
}
rep(j,1,n+1){
if(v[row][j] == 0 && !vis[val][j]){
v[row][j] = 1;
vis[val][j] = 1;
if(row+1 < n){
dfs(val,row+1);
}else{
dfs(val+1,1);
}
vis[val][j] = 0;
v[row][j] = 0;
}
}
} int main(){
// usefile();
cin>>n;
rep(j,1,n+1){
v[0][j]=j;
vis[j][j]=1;
}
rep(i,1,n){
v[i][1]=i+1;
vis[i+1][1]=1;
}
dfs(1,1);
rep(i,1,n){
anscnt*=i;
}
cout<<anscnt<<endl;
return 0;
}

网上搜了一下方法,有一种是 靠循环节 置换圈 大概群论相关

而我决定 放弃,打表吧XD

#include <bits/stdc++.h>
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--) using namespace std; const string filename = "latin"; void usefile(){
freopen((filename+".in").c_str(),"r",stdin);
freopen((filename+".out").c_str(),"w",stdout);
} int n; map<int,long long >ans; int main(){
usefile();
ans[2]= 1;
ans[3]= 2;
ans[4]= 24;
ans[5]= 1344;
ans[6]= 1128960;
ans[7]= 12198297600;
cin>>n;
cout<<ans[n]<<endl;
return 0;
}

Closed Fences

题目大意

计算几何

逆时针给一系列点(<=200个),坐标范围(| |<=2^16)检查 这些点是否能围成一个围栏

如果可行,再给一点 输出 从该点发出射线,能照到的线段 (只要部分能被照到 就输出整段)

如果 给的点,和一条线段共线,视作无法照到

题解

看上去像是可以枚举,按照角度,200次遍历射线,每次射线遍历200条边,一共就n方左右的复杂度

我们先 过一边所有线段如果不相交,那么可以围成(这里没有判断顺时针还是逆时针)

然后枚举所有线段,对每一条线段1000等分,枚举从给定的点 向等分点是否与其它线段有交点

时间复杂度O(n*n*1000);

[这题的核心还是说写计算几何的算法

#include <bits/stdc++.h>
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--) using namespace std; const string filename = "fence4"; void usefile(){
freopen((filename+".in").c_str(),"r",stdin);
freopen((filename+".out").c_str(),"w",stdout);
} pair<int,int> p;
pair<int,int> P[210];
int N; double cross(pair<double,double> a,pair<double,double> b){
return a.first*b.second-a.second*b.first;
} pair<double,double> operator + (pair<double,double> a,pair<double,double> b) {
return {a.first+b.first,a.second+b.second};
} pair<double,double> operator - (pair<double,double> a,pair<double,double> b) {
return {a.first-b.first,a.second-b.second};
} bool isIntersect(pair<pair<double,double>,pair<double,double>> line1,pair<pair<double,double>,pair<double,double>> line2){
return !(
(cross(line1.first -line2.first,line2.second-line2.first) > 0) ==
(cross(line1.second-line2.first,line2.second-line2.first) > 0) ||
(cross(line2.first -line1.first,line1.second-line1.first) > 0) ==
(cross(line2.second-line1.first,line1.second-line1.first) > 0)
); } bool isValid(){
rep(i,0,N){
rep(j,i+2,N){
if(i == 0 && j == N-1)continue;
if(isIntersect({P[i],P[i+1]}, {P[j],P[(j+1)%N]})){
return false;
}
}
}
return true;
} // 共线
bool isColine(int idx){
return cross(P[idx]-P[(idx+1)%N],p) == cross(P[idx],P[(idx+1)%N]);
} bool isSeen(int idx){
int x1 = P[idx].first;
int y1 = P[idx].second;
int nsegments = 1000;
rep(i,1,nsegments){
pair<double,double> point_ = {
x1 + i * 1.0 / nsegments * (P[(idx + 1) % N].first - x1),
y1 + i * 1.0 / nsegments * (P[(idx + 1) % N].second - y1)};
bool blocked = false;
rep(j,0,N){
if(j == idx) {
continue;
}
if(isIntersect({p,point_}, {P[j],P[(j+1)%N]})){
blocked = true;
break;
}
}
if(!blocked) {
return true;
}
}
return false;
} vector<int> ans;
int main(){
usefile();
scanf("%d", &N);
scanf("%d %d", &p.first,&p.second);
rep(i,0,N){
scanf( "%d %d", &P[i].first, &P[i].second);
}
if(!isValid()) {
printf( "NOFENCE\n");
return 0;
}
rep(i,0,N){
if(!isColine(i) && isSeen(i)) {
ans.push_back(i);
}
}
if(ans.size() >= 2 && ans[ans.size() - 2] == N - 2){
ans[ans.size() - 2] = N - 1;
ans[ans.size() - 1] = N - 2;
}
printf("%d\n", int(ans.size()));
rep(i,0,ans.size()){
if(ans[i] == N - 1) {
printf("%d %d %d %d\n", P[0].first, P[0].second, P[ans[i]].first, P[ans[i]].second);
}else{
printf( "%d %d %d %d\n", P[ans[i]].first, P[ans[i]].second, P[ans[i] + 1].first, P[ans[i] + 1].second);
}
}
return 0;
}

Betsy's Tour

题目大意

n x n(n<=7) 的矩阵,从左上走到坐下,每个格子最多经过一次的方案数

题解

暴搜+打表

插头dp ? 像是

实现了一下 果然过了,注意处理n = 1

插头dp的话 直接百度文库 应该能搜到不少文章,我感觉我的边界处理状态转移的代码写得好丑QAQ

  1. 这里的一个技巧是,想象在左边在多出一列,把这列从上连到下,这样原题就变成确定了一部分路线的欧拉回路的插头dp了,这样 起始和终点的就也和中间的过程块,看作联通其它两个块的 来处理了
  2. 状态表示,最无脑的是,相同数字,但是 这样的话状态转移会比较难写 比如100120332,注意到我们会一直维持合法性,所以可以用左右括号表示(__)(_()),这样的化就是3进制即可,然后4进制更容易操作,比如我下面用的位运算<<2 或 >>2
  3. 在上面两个优化下 初始状态是(______)这样的

时间复杂度O(i*j*state) = O(7*7*3^7)

#include <bits/stdc++.h>
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--) using namespace std; const string filename = "betsy"; void usefile(){
freopen((filename+".in").c_str(),"r",stdin);
freopen((filename+".out").c_str(),"w",stdout);
} int n; // 中间的 每个块 连接 两个方向, map<pair<int,long long>,long long> res; int get_state(long long state,int pos){
return (state >> (2*pos)) % 4;
} int set_state(long long state,int pos){
return state << (2*pos);
} // (( ) ())
// block: 的2进制位 0b3210
// 3
// 0 2
// 1
long long insert_state(long long old_state,int pos,int block){
int arr[10];
// 栈计算括号对
int p[10];
int stk[10];
int stki = 0;
rep(i,0,n+1){
arr[i] = get_state(old_state,i);
if(arr[i] == 0)continue;
if(arr[i] == 1)stk[stki++]=i;
if(arr[i] == 2){
p[i] = stk[stki-1];
p[stk[stki-1]] = i;
stki--;
}
}
int cnt = 0;
rep(i,0,4){
cnt+= !!(block & (1<<i));
}
assert(cnt == 2);
// 插入的块和 被插入的位置 同时有或没有
if( (!(block & 0b1000) != !arr[pos]) || (!(block & 0b0001) != !arr[pos+1]) ){
return -1;
}
// 原来为空 新建边
if( (block & 0b0100) && (block & 0b0010)){
arr[pos] = 1;
arr[pos+1] = 2;
}else if( (block & 0b0100) || (block & 0b0010) ){ // 引出一条原来的边
if(block & 0b0100){
arr[pos] = arr[pos]+arr[pos+1];
arr[pos+1] = 0;
}else {
arr[pos+1] = arr[pos]+arr[pos+1];
arr[pos] = 0;
}
}else{ // 把原来两段 连接起来
if(arr[pos] == 1 && arr[pos+1] == 2){
arr[pos] = 0 ;
arr[pos+1] = 0 ;
}else{
arr[pos] = 0;
arr[pos+1] = 0;
int p1 = p[pos];
int p2 = p[pos+1];
if(p1 > p2)swap(p1,p2);
arr[p1] = 1;
arr[p2] = 2;
}
}
long long new_state = 0;
rep(i,0,n+1){
new_state += set_state(arr[i],i);
}
return new_state;
} long long dp(int idxi,int idxj,long long state){
long long &ret = res[{(idxi<<3)+idxj,state}];
if(ret != 0){
return ret;
}
// 右下角允许自连
if(idxj == n-1 && idxi == n-1) {
return ret = (get_state(state,n-1) == 1 && get_state(state,n) == 2);
}
// 过程中不允许自连
//
if (get_state(state,idxi) == 1 && get_state(state,idxi+1) == 2)return 0;
rep(i,0,4){
rep(j,i+1,4){
int new_state = insert_state(state,idxi,(1<<i)+(1<<j));
if(new_state == -1)continue;
// 最后一列
if(idxj == n-1) {
if(get_state(new_state,idxi) != 0)continue;
}
// 最后一行
if(idxi == n-1){
if(get_state(new_state,idxi+1) != 0)continue;
new_state <<=2;
ret+=dp(0,idxj+1,new_state);
}else{
ret+=dp(idxi+1,idxj,new_state);
}
}
}
// printf("(%d,%d) {%lld,%lld,%lld} = %lld\n",idxi,idxj,(state)%4,(state>>2)%4,(state>>4)%4,ret);
return ret;
} int main(){
usefile();
cin>>n;
if(n == 1){
cout<<1<<endl;
}else{
cout<<dp(0,0,set_state(1,1)+set_state(2,n))<<endl;
}
return 0;
}

总结

6.5章其实有5个题,但后面两题 我很久很久很就以前做了 就不想再做一次了,所以这里只写了3题

本文其它链接

牛客:https://blog.nowcoder.net/n/c7f0a70d69254c9180dd0b7e475d1248

github:https://yexiaorain.github.io/Blog/2019-07-07-USACO-6.5/

USACO 6.5 章节 世界上本没有龙 屠龙的人多了也便有了的更多相关文章

  1. 为什么我会认为SAP是世界上最好用最牛逼的ERP系统,没有之一?

    为什么我认为SAP是世界上最好用最牛逼的ERP系统,没有之一?玩过QAD.Tiptop.用友等产品,深深觉得SAP是贵的有道理! 一套好的ERP系统,不仅能够最大程度承接适配企业的管理和业务流程,在技 ...

  2. Nivo Slider - 世界上最棒的 jQuery 图片轮播插件

    Nivo Slider 号称世界上最棒的图片轮播插件,有独立的 jQuery 插件和 WordPress 插件两个版本.目前下载量已经突破 1,800,000 次!jQuery 独立版本的插件主要有如 ...

  3. 世界上不存在什么RedBSD,SuseBSD或者ArchBSD,Turb...

    世界上不存在什么RedBSD,SuseBSD或者ArchBSD,TurboBSD之类的东西.

  4. hdu---(4515)小Q系列故事——世界上最遥远的距离(模拟题)

    小Q系列故事——世界上最遥远的距离 Time Limit: 500/200 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)T ...

  5. Git是目前世界上最先进的分布式版本控制系统

    一:Git是什么? Git是目前世界上最先进的分布式版本控制系统. 二:SVN与Git的最主要的区别? SVN是集中式版本控制系统,版本库是集中放在中央服务器的,而干活的时候,用的都是自己的电脑,所以 ...

  6. 世界上最方便的SharePoint移动客户端--Rshare

    Rshare我试用了一段时间,同时也测试了其他家产品,使用后的感觉是Rshare无愧于世界上最方面的SharePoint移动客户端. 1.界面设计很方便,设计中充分考虑到移动客户的使用习惯及喜好,设计 ...

  7. HDU-4515 小Q系列故事——世界上最遥远的距离

    小Q系列故事——世界上最遥远的距离 Time Limit: 500/200 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) ...

  8. Smartdraw世界上最流行的商业绘图软件

    Smartdraw 更多图片(5张) SmartDraw是世界上最流行的商业绘图软件.2006 年获美国政府司法部 (U.S. Department of Justice) 专用软件,2007获美国政 ...

  9. JavaScript: 世界上最被误解的语言|Douglas Crockford

    JavaScript: 世界上最被误解的语言 JavaScript: The Wrrrld's Most Misunderstood Programming Language Douglas Croc ...

随机推荐

  1. knn算法手写字识别案例

    import pandas as pd import numpy as np import matplotlib.pyplot as plt import os from sklearn.neighb ...

  2. 一波骚操作,我把 SQL 执行效率提高了 10,000,000 倍!

    作者:风过无痕-唐 http://www.cnblogs.com/tangyanbo/p/4462734.html 场景 我用的数据库是mysql5.6,下面简单的介绍下场景 课程表: create  ...

  3. mysql 5.7 事务隔离级别

    事务的隔离级别分为:未提交读(read uncommitted).已提交读(read committed).可重复读(repeatable read).串行化(serializable). 未提交读: ...

  4. Yii框架怎么寻找对应视图

    render()内容; public function render($view,$data=null,$return=false) { if($this->beforeRender($view ...

  5. JVM(13)之 阶段回顾

    开发十年,就只剩下这套架构体系了! >>>   各位小伙伴,到上一篇博文为止,我们的内存模型相关知识就已经讲完了!讲!完!了!不知道大家吸收了多少,这里我们简单的来回顾一下吧!    ...

  6. Css3-颜色 color

    一.颜色 RGBA RGB是一种色彩标准,是由红(R).绿(G).蓝(B)的变化以及相互叠加来得到各式各样的颜色.RGBA是在RGB的基础上增加了控制alpha透明度的参数. 语法:color:rgb ...

  7. 廖雪峰Python电子书总结

    函数 1.注意:函数的默认参数必须指向不可变对象 未修改前: def add_end(L=[]): L.append('END') return L 存在的问题:如果连续调用多次,会出现多个 'END ...

  8. 【彩彩只能变身队(第七组)】Beta版本

    本篇博客包括前期博文汇总.任务墙.团队管理细节与交流细节.代码管理.Beta阶段冲刺.团队总结.用户使用报告.Postmortem报告. 服务器网址:http://47.106.227.154/ 彩彩 ...

  9. git兼容svn与hg功能

    本地.git库 远程:push  提交以后push才可以到远程库

  10. Django--Forms组件使用

    Forms组件的使用 在html表单验证中,需要通过各种信息的验证,比如注册界面的姓名.密码.邮箱.电话等的验证,是否符合定义好的规则,不可能每次都要取出对应的字段一一判断,django内置了Form ...