moc3型live2D如何在网页上使用

前言 之前搞网页 Live2d 模型的时候在网上找了很多文章,但大部分都只支持moc格式的模型,不支持moc3格式的模型。 最近在Github上看到这个项目AzurLaneL2DViewer, 使用前请查看live2dcubismcore的许可协议 HCLonely Live2dV3 021efa , up-to-date HCLonely Live2dV3 021efa , up-to-date 使用方法 在标签内添加如下内容:

<div class="Canvas" style="position:fixed;right:250px; bottom: -100px;z-index: 99999999" id="L2dCanvas"></div>
<!------ 依赖 JS ------>
<!---- 可选 ---->
<!-- 兼容低版本浏览器 -->
<script src="http://www.xiaocongyu.com/live2d/js/polyfill.min.js"> </script>
<!-- 音频播放兼容 -->
<script src="http://www.xiaocongyu.com/live2d/js/howler.min.js"></script>
<!---- 必需 ---->
<script src="http://www.xiaocongyu.com/live2d/js/live2dcubismcore.min.js"></script>
<script src="http://www.xiaocongyu.com/live2d/js/pixi.min.js"></script>
<!-- live2dv3.js -->
<script src="http://www.xiaocongyu.com/live2d/yu3/live2dva.min.js"></script>
<!------ 加载Live2d模型 ------>
<script>
window.onload = () => {
    new l2dViewer({
        el: document.getElementById('L2dCanvas'), // 要添加Live2d的元素, 支持dom选择器和jq选择器
			//basePath: 'https://cdn.jsdelivr.net/npm/live2dv3@latest/assets',
        //modelName: 'biaoqiang_3',
        basePath: 'http://www.xiaocongyu.com/live2d', // 模型根目录
        modelName: 't4', // 模型名称
			width: 200,
			height: 600,
			mobileLimit: false,
        sounds: [ // 触摸播放声音
            'http://www.xiaocongyu.com/live2d/sounds/buhaixiuma.mp3' ,// 也可以是网址
				 'http://www.xiaocongyu.com/live2d/sounds/haixiu.mp3'
        ]
		
    })
}
</script>

HTML 复制 参数 参数 类型 描述 默认 el [必需] DOM 对象或 jQuery 对象 要挂载 Live2d 模型的元素, 支持 DOM 选择器和 jQuery 选择器,例:document.getElementById(‘L2dCanvas’)或document.querySelector(‘#L2dCanvas’)或$(‘#L2dCanvas’) null basePath [必需] String 模型根目录 null modelName [必需] String 模型目录 null width [可选] Number Canvas 宽度,单位:px 500 height [可选] Number Canvas 高度,单位:px 300 sizeLimit [可选] Boolean 当窗口大小小于设置的宽或高时不加载模型 false mobileLimit [可选] Boolean 移动端不加载模型 false sounds [可选] Array 触摸播放声音, 留空则不播放 null 方法 loadModel(modelName?) 重新加载/更换模型

特征选择和降维

1、相同点和不同点

  特征选择和降维有着些许的相似点,这两者达到的效果是一样的,就是试图去减少特征数据集中的属性(或者称为特征)的数目;但是两者所采用的方式方法却不同:降维的方法主要是通过属性间的关系,如组合不同的属性得新的属性,这样就改变了原来的特征空间;而特征选择的方法是从原始特征数据集中选择出子集,是一种包含的关系,没有更改原始的特征空间。

2、降维的主要方法

特征选择的目标

  引用自吴军《数学之美》上的一句话:一个正确的数学模型应当在形式上是简单的。构造机器学习的模型的目的是希望能够从原始的特征数据集中学习出问题的结构与问题的本质,当然此时的挑选出的特征就应该能够对问题有更好的解释,所以特征选择的目标大致如下:

  • 提高预测的准确性
  • 构造更快,消耗更低的预测模型
  • 能够对模型有更好的理解和解释

特征选择的方法

  主要有三种方法:

1、Filter方法

  其主要思想是:对每一维的特征“打分”,即给每一维的特征赋予权重,这样的权重就代表着该维特征的重要性,然后依据权重排序。

  主要的方法有:

2、Wrapper方法

  其主要思想是:将子集的选择看作是一个搜索寻优问题,生成不同的组合,对组合进行评价,再与其他的组合进行比较。这样就将子集的选择看作是一个是一个优化问题,这里有很多的优化算法可以解决,尤其是一些启发式的优化算法,如GA,PSO,DE,ABC等,详见“优化算法——人工蜂群算法(ABC)”,“优化算法——粒子群算法(PSO)”。

  主要方法有:recursive feature elimination algorithm(递归特征消除算法)

3、Embedded方法

  其主要思想是:在模型既定的情况下学习出对提高模型准确性最好的属性。这句话并不是很好理解,其实是讲在确定模型的过程中,挑选出那些对模型的训练有重要意义的属性。

  主要方法:正则化,可以见“简单易学的机器学习算法——岭回归(RidgeRegression)”,岭回归就是在基本线性回归的过程中加入了正则项。

总结以及注意点

  这篇文章中最后提到了一点就是用特征选择的一点Trap。个人的理解是这样的,特征选择不同于特征提取,特征和模型是分不开,选择不同的特征训练出的模型是不同的。在机器学习=模型+策略+算法的框架下,特征选择就是模型选择的一部分,是分不开的。这样文章最后提到的特征选择和交叉验证就好理解了,是先进行分组还是先进行特征选择。

  答案是当然是先进行分组,因为交叉验证的目的是做模型选择,既然特征选择是模型选择的一部分,那么理所应当是先进行分组。如果先进行特征选择,即在整个数据集中挑选择机,这样挑选的子集就具有随机性。

  我们可以拿正则化来举例,正则化是对权重约束,这样的约束参数是在模型训练的过程中确定的,而不是事先定好然后再进行交叉验证的。

  以上是我学习的一点感悟,希望有更多的人一起参加讨论,如有哪里写的不对或者有其他任何问题,也希望能够留言。

参考文献:

An Introduction to Feature Selection 地址:http://machinelearningmastery.com/an-introduction-to-feature-selection

Java中Map根据键值(key)或者值(value)进行排序实现

我们都知道,java中的Map结构是key->value键值对存储的,而且根据Map的特性,同一个Map中 不存在两个Key相同的元素,而value不存在这个限制。换句话说,在同一个Map中Key是唯一的,而value不唯一。Map是一个接口,我们不能 直接声明一个Map类型的对象,在实际开发中,比较常用的Map性数据结构是HashMap和TreeMap,它们都是Map的直接子类。如果考虑到存取 效率的话,建议使用HashMap数据结构,而如果需要考虑到Key的顺序,建议使用TreeMap,但是TreeMap在删除、添加过程中需要排序,性能比较差。

1 、 以Key进行排序
我们可以声明一个TreeMap对象

Map<Integer, Person> map = new TreeMap<Integer, Person>();

然后往map中添加元素,可以通过输出结果,可以发现map里面的元素都是排好序的

//遍历集合for (Iterator<Integer> it = map.keySet().iterator(); it.hasNext();) {Person person = map.get(it.next());System.out.println(person.getId_card() + " " + person.getName());}

我们也可以声明一个HashMap对象,然后把HashMap对象赋值给TreeMap,如下:

Map<Integer, Person> map = new HashMap<Integer, Person>();TreeMap treemap = new TreeMap(map);

2、以Value进行排序
先声明一个HashMap对象:

Map<String, Integer> map = new HashMap<String, Integer>();

然后我们可以将Map集合转换成List集合中,而List使用ArrayList来实现如下:

List<Entry<String,Integer>> list =new ArrayList<Entry<String,Integer>>(map.entrySet());

最后通过Collections.sort(List l, Comparator c)方法来进行排序,代码如下:

Collections.sort(list, new Comparator<Map.Entry<String, Integer>>() {public int compare(Map.Entry<String, Integer> o1,Map.Entry<String, Integer> o2) {return (o2.getValue() - o1.getValue());}});

上述代码是讲map中的value按照逆序排序,如果需要按照升序进行排序的话,只需要修改o2.getValue() – o1.getValue()为o1.getValue() – o2.getValue()即可

关于欧拉函数的一些理解与拓展

很早之前就只知道一点欧拉函数的使用,现在来总结一下,有哪些我没懂的和我懂了的

欧拉定理

欧拉定理,也称费马-欧拉定理,若n,a为正整数,且n,a互质,即gcd(a,n) = 1,则a^φ(n) ≡ 1 (mod n)

欧拉函数

欧拉函数是求小于等于n的数中与n互质的数的数目  

如果n是质数那么1到n-1所有数都是与n互质的,所以φ(n) = n-1如果n是合数。。。自己算吧例如φ(8)=4,因为1,3,5,7均和8互质

请思考以下问题:

任意给定正整数n,请问在小于等于n的正整数之中,有多少个与n构成互质关系?(比如,在1到8之中,有多少个数与8构成互质关系?)

计算这个值的方法就叫做欧拉函数,以φ(n)表示。在1到8之中,与8形成互质关系的是1、3、5、7,所以 φ(n) = 4。

φ(n) 的计算方法并不复杂,但是为了得到最后那个公式,需要一步步讨论。

第一种情况

如果n=1,则 φ(1) = 1 。因为1与任何数(包括自身)都构成互质关系。

第二种情况

如果n是质数,则 φ(n)=n-1 。因为质数与小于它的每一个数,都构成互质关系。比如5与1、2、3、4都构成互质关系。

第三种情况

如果n是质数的某一个次方,即 n = p^k (p为质数,k为大于等于1的整数),则

2015-08-04/55c0573f4a25a

比如 φ(8) = φ(2^3) =2^3 – 2^2 = 8 -4 = 4。

这是因为只有当一个数不包含质数p,才可能与n互质。而包含质数p的数一共有p^(k-1)个,即1×p、2×p、3×p、…、p^(k-1)×p,把它们去除,剩下的就是与n互质的数。

上面的式子还可以写成下面的形式:

2015-08-04/55c0578076585

可以看出,上面的第二种情况是 k=1 时的特例。

第四种情况

如果n可以分解成两个互质的整数之积,

n = p1 × p2

φ(n) = φ(p1p2) = φ(p1)φ(p2)

即积的欧拉函数等于各个因子的欧拉函数之积。比如,φ(56)=φ(8×7)=φ(8)×φ(7)=4×6=24。

这一条的证明要用到“中国剩余定理”,这里就不展开了,只简单说一下思路:如果a与p1互质(a<p1),b与p2互质(b<p2),c与p1p2互质(c<p1p2),则c与数对 (a,b) 是一一对应关系。由于a的值有φ(p1)种可能,b的值有φ(p2)种可能,则数对 (a,b) 有φ(p1)φ(p2)种可能,而c的值有φ(p1p2)种可能,所以φ(p1p2)就等于φ(p1)φ(p2)。

第五种情况

2015-08-04/55c057f99f735

因为任意一个大于1的正整数,都可以写成一系列质数的积。

2015-08-04/55c05835ca6e2

根据第4条的结论,得到

再根据第3条的结论,得到

2015-08-04/55c05871f2594

也就等于

2015-08-04/55c058b16129e

这就是欧拉函数的通用计算公式。比如,1323的欧拉函数,计算过程如下:

2015-08-04/55c059446c936

欧拉公式

还有一个欧拉公式eix = cosx + isinx

把x代入公式就是, eiπ + 1 = 0

引用一个名人的话(我忘了是谁( ̄▽ ̄lll)):”它把自然对数e,虚数i,无理数π,自然界中的有和无(1和0)巧妙的结合了起来,上帝如果不存在,怎么会有这么优美的公式。如何见到它第一眼的人没有看到它的魅力,那它一定成不了数学家”

费马小定理

由欧拉函数的特例,如果n是质数,则可得欧拉定理 a^(n-1)≡ 1 (mod n)

AbemaTV-无料インターネットテレビ局 附:破解教程(支持部分日系锁区限制软件)

注:仅破解区域限制,观看还需挂日本IP梯子 ,在此不提供梯子。

AbemaTV-无料インターネットテレビ局”是一个日本网络电视台“アベマTV”出的视频 App,里面不少节目和视频都是免费的。

但是我安装后发现这个 App 有区域限制,启动时全屏显示 “このサービスはお住まいの地域からはご利用になれません。”提示,无法继续(已经用了日本IP的shadowsocks)。

简单地尝试下破解了这个 App 的区域限制。步骤如下:

1. 从 apkpure 下载 AbemaTV app 最新版的 apk

2. 用 apktool 这个工具解包下载的 apk. apktool 是一个 java 包,需要安装 Java 运行。

java -jar apktool_2.2.4.jar d “AbemaTV 无料インターネットテレビ局_v3.5.1_apkpure.com.apk”

3. 解包后的文件在当前目录下 “AbemaTV 无料インターネットテレビ局_v3.5.1_apkpure.com/” 文件夹。其中,res/ 是资源文件,smali/ 和 smali_classes2/ 是 java 源码编译后的 smali 文件。这个 app 好像没怎么加密什么的。

在整个目录里搜索 “このサービスはお住まいの地域からはご利用になれません。” 字符串,找到:

<string name=”error_abroad_description”>このサービスはお住まいの地域からはご利用になれません。</string>

搜索 error_abroad_description,找到:res/values/public.xml:
<public type=”string” name=”error_abroad_description” id=”0x7f0a0114″ />

搜索 0x7f0a0114,找到 smali_classes2tvabemacomponentsfragmenta.smali:

.class public Ltv/abema/components/fragment/a;
.super Ltv/abema/components/fragment/u;
.source “AbroadFragment.java”

const v1, 0x7f0a0114
invoke-virtual {v0, v1}, Landroid/widget/TextView;->setText(I)V

可以看到,这是一个 Fragment 类编译成的 smali 文件,当 app 检测到当前设备是日本以外区域(检测方法未知,可能是检测手机sim卡运营商信息)时就在当前 activity 上加载这个全屏 fragment 以阻止使用,所以最简单的破解方法就是把这个“创建并显示 Fragment”部分代码去掉。

搜索 “Ltv/abema/components/fragment/a”,找到:
smalitvabemaajk.smali

.line 202
const-class v0, Ltv/abema/components/fragment/a;
invoke-virtual {p0, v0}, Ltv/abema/a/jk;->I(Ljava/lang/Class;)V

看起来就是这里了,将这几行用 “#” 注释掉。

4. 最后,用 apktool 重新打包修改后文件生成 apk,参数就是之前解包apk文件所在目录

java -jar apktool_2.2.4.jar b “AbemaTV 无料インターネットテレビ局_v3.5.1_apkpure.com”

生成的 apk 在 AbemaTV 无料インターネットテレビ局_v3.5.1_apkpure.com/dist 文件夹下。

生成的 apk 是未签名的,无法直接安装。可以手工用 java bin目录下 keytool 工具生成密钥,jarsigner 工具给 apk 签名。(具体过程网上资料很多);也可以用直接用 apk-signer 这个图形化工具来进行

最后在手机上安装生成的 AbemaTV_v3.5.1_SIGNED_UNALIGNED.apk 即可,实测能够正常进入主界面并观看视频,搞定。

修改 app 包后无法使用 Google Play IAP 内购功能。最完美的破解 root 检测方法仍然是安装 XPosed + rootcloak

类似方法解除 Hulu 日本Android app的 root检测:

由错误提示“OSの整合性チェックに失败しました。Root権限を取得している场合、起动できません。”跟踪找到某个Fragment:


const-string v2, “su”

invoke-virtual {v1, v2}, Ljava/lang/Runtime;->exec(Ljava/lang/String;)Ljava/lang/Process;
:try_end_0
.catch Ljava/io/IOException; {:try_start_0 .. :try_end_0} :catch_0
.catchall {:try_start_0 .. :try_end_0} :catchall_0

move-result-object v0

const v1, 0x7f0900e8

这里通过运行 su 检测是否有异常来判断机器是否已 root,所以最简单的移除方法就是把 “su” 随便改成个不存在对应命令的名字。

如果App是通过检测sim卡运营商限制区域的,那么应该可以通过改手机运营商代码来骗过(需要root),这样就不需要改apk了。日本主要移动ISP的运营商代码
docomo:4401020
softbank: 4402081
au: 4540492, 4405014

附上下载链接:

链接:https://pan.baidu.com/s/12RU3xFjaA-_rCr2kaiTFEA
提取码:o2yn

合并一行多列单元格

  • 合并1行多列可以使用\multicolumn{cols}{pos}{text}来实现
\documentclass[a4paper,12pt]{report}
\usepackage[UTF8,nopunct]{ctex}

\begin{document}

\begin{table}
	\centering
	\begin{tabular}{|c|c|c|c|}
		\hline
		\multicolumn{2}{|c|}{合并一行两列} & 三 & 四 \\
		\hline
		1 & 2 & 3 & 4 \\
		\hline
	\end{tabular}
\end{table}

\end{document}

合并多行一列单元格

  • 合并多行1列单元格可以用multirow包中的\multirow{rows}{width}{text}来实现
  • 注意这里的第2个参数是{width},与\multicolumn第2个参数不同。如果不确定{width}需要填什么,就将其替换为*,如代码中所示

这次ACM的题感觉思考得太慢了,脑子好久不动,思考能力也下降了

来总结一下做第一题的思路吧

先贴题目

Problem A: zbj的糖果

Time Limit: 1 Sec  Memory Limit: 128 MB
Submit: 101  Solved: 12
[Submit][Status][Web Board]

Description

现在zbj跟n个小朋友在玩一个游戏。首先,这n个小朋友的编号分别为1,2,3…n,每个小朋友手里都有不同数量的糖果,每个小朋友手里的糖果数量刚好等于他们的编号。

现在他们按顺序围着一张桌子坐下,即 x 的两边分别坐的是x – 1 和 x + 1,n 和 1 相邻。

现在zbj可以从编号为1的小朋友开始,把他们手里的糖果拿走,当然为了游戏乐趣,对于每一轮游戏,zbj决定规定一个数字 k ,表示他每隔 k 个小朋友,就会拿走当前小朋友手里的糖果,当某次又要拿走编号为 1 的小朋友手里的糖果时,他就会停止这轮游戏。

比如有6个小朋友,规定k为4,即n=6,k=4,zbj拿糖果的顺序为:1→5→3→1 

现在zbj想知道,按照这样的游戏规则,最多能拿到手的糖果总数有几种不同的情况?

Input

输入只包含一个正整数n(2<=n<=10^9)表示有n个小朋友。

Output

zbj最后能拿到手里的糖果总数的数量集合,按升序输出,两个数字中间用空格隔开,末尾没有空格。

Sample Input

6

Sample Output

1 5 9 21

HINT

对于样例的解释。有以下6种情况

题目理解:找一下规律就知道,先将所有最小因子求出来,然后列出所有可能的取法

解题代码:

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
int coun=0;
ll s[10000];
ll f(int i,int n){
    ll sum=0,t;
    t=n/i;
    sum=t+i*(t-1)*t/2;
    return sum;
}

void g(int pr[],int j,int n,ll s[],ll sum){
   for(int i=0;i<j;i++){
        sum*=pr[i];
        if(sum>=n) {break;}
        if(n%sum!=0) {sum/=pr[i];continue;}
        s[coun++]=f(sum,n);
        g(&pr[i],j-i,n,s,sum);
        sum/=pr[i];
   }
}

int main(){
    int pr[10000];
    int i,j=0,t,n;
    cin>>n;
    t=n;
    for(i=2;i<=t;i++){
        if(t%i==0) {
            while(t%i==0&&t) t/=i;
            pr[j++]=i;
        }
    }
  /*  for(i=0;i<j;i++){
        cout<<pr[i]<<" ";
    }*/
    g(pr,j,n,s,1);
    s[coun++]=f(1,n);
    s[coun++]=1;
    sort(s,s+coun);
    cout<<s[0];
    for(i=1;i<coun;i++){
        cout<<" "<<s[i];
    }
    cout<<endl;
    return 0;
}

有些细节的地方自己以后再来理解一下