ACM-ICPC Asia Beijing Regional Contest 2018 Reproduction hihocoder1870~1879

A

签到,dfs 或者 floyd 都行。

#include<bits/stdc++.h>
using namespace std; typedef long long LL;
typedef long double LD;
typedef pair<int,int> pii;
typedef pair<LL,int> pli;
const int SZ = 1e5 + 10;
const int INF = 1e9 + 10;
const int mod = 1e9 + 7;
const LD eps = 1e-8; LL read() {
LL n = 0;
char a = getchar();
bool flag = 0;
while(a > '9' || a < '0') { if(a == '-') flag = 1; a = getchar(); }
while(a <= '9' && a >= '0') { n = n * 10 + a - '0',a = getchar(); }
if(flag) n = -n;
return n;
} string S1[22],S2[22];
int n;
int f[111][111]; void work() {
map<string,int> mp;
int tot = 0;
for(int i = 1;i <= n;i ++) {
string s1 = S1[i],s2 = S2[i];
if(!mp[s1]) mp[s1] = ++ tot;
if(!mp[s2]) mp[s2] = ++ tot;
} for(int i = 1;i <= tot;i ++) {
for(int j = 1; j <= tot;j ++) {
f[i][j] = 0;
}
} for(int i = 1;i <= n;i ++) {
string s1 = S1[i],s2 = S2[i];
int x = mp[s1],y = mp[s2];
if(f[y][x]) {
cout << s1 << " " << s2 << endl;
return ;
}
f[x][y] = 1;
for(int k = 1;k <= tot;k ++) {
for(int u = 1;u <= tot;u ++) {
for(int v = 1;v <= tot;v ++) {
if(f[u][k] && f[k][v]) {
f[u][v] = 1;
}
}
}
}
for(int u = 1;u <= tot;u ++) {
for(int v = 1;v <= tot;v ++) {
if(f[u][v]) {
if(u == v || f[v][u]) {
cout << s1 << " " << s2 << endl;
return ;
}
}
}
}
/* for(int u = 1;u <= tot;u ++,puts(""))
for(int v = 1;v <= tot;v ++)
printf("%d ",f[u][v]);
puts("");*/
}
puts("0");
return ;
} int main() {
while(~scanf("%d",&n)) {
for(int i = 1;i <= n;i ++) {
string s1,s2;
cin >> s1 >> s2;
S1[i] = s1;
S2[i] = s2;
}
work();
}
}

B

阅读题,模拟,坑点多,WA了好多发,换了个写法就过了,不知道为什么

C

题意:定义 (a,b,c) 为一组勾股数,c 是斜边长度,且 (a,b,c) 与 (b,a,c) 看做一组。问 c<=n 的三元组有多少对。 \(n \le 10^9\)

key:推公式

我真的是惊了,为什么要出这种带了板子就会的题。

首先你要知道勾股数的构造才能做这个题,即 \(a=m^2-n^2,b=2mn,c=m^2+n^2\) 。所有勾股数不好算,所以我们对本原勾股数计数,乘上个倍数即可。在上式中, \((a,b,c)\) 为一组本原勾股数当且仅当 $\gcd(m,n)=1 \text{且 \(m,n\)为一奇一偶}$ 。

设 \(f(n)\) 为以 n 为斜边的三元组对数, \(g(n)\) 为以 n 为斜边的本原勾股数个数,\(F,G\) 为对应的前缀和,那么有:

\[f = g \times 1 \to F=\sum_{1 \le i\le n}G(n/i) \\
G(n) = \sum_{1\le x\le N} \sum_{1 \le y \le N} [x^2+y^2 \le N][\gcd(x,y)=1][\text{x is odd, y is even}]
\]

然后就对 G 随便推一波就行了。形式是一个调和级数。

不预处理的话复杂度是 \(O(Tn^{3/4}\ln n)\),预处理前根号下三分之二次方的复杂度就变成 \(O(Tn^{2/3}\ln n)\) 。预处理就直接用上面给出的这个 G ,随便积分一下算出来预处理前 B 项的复杂度是 \(O(B \ln B)\) 。实测了一下大概取 \(10^7\) 比较优,十组 \(10^9\) 只跑 0.6s 左右。

#include<bits/stdc++.h>
using namespace std; typedef unsigned long long ULL;
typedef long long LL;
typedef long double LD;
typedef pair<int,int> pii;
typedef pair<LL,int> pli;
const int SZ = 1e7 + 10;
const int INF = 1e9 + 10;
const int mod = 1e9 + 7;
const LD eps = 1e-8; LL read() {
LL n = 0;
char a = getchar();
bool flag = 0;
while(a > '9' || a < '0') { if(a == '-') flag = 1; a = getchar(); }
while(a <= '9' && a >= '0') { n = n * 10 + a - '0',a = getchar(); }
if(flag) n = -n;
return n;
} int preG[SZ];
const int MAXN = 1e7;
int mu[100100];
bool vis[100100];
int pri[100100]; void preWork(int n) {
for(int x = 1;x * x <= n;x += 2) {
for(int y = 2;x * x + y * y <= n;y += 2) {
if(__gcd(x,y) == 1)
preG[x*x+y*y] ++;
}
}
for(int i = 1;i <= n;i ++) preG[i] += preG[i-1]; n = 100000;
mu[1] = 1;
for(int i = 2;i <= n;i ++) {
if(!vis[i]) pri[++ pri[0]] = i,mu[i] = -1;
for(int j = 1,m;j <= pri[0] && (m=i*pri[j]) <= n;j ++) {
vis[m] = 1;
if(i%pri[j] == 0) {
mu[m] = 0;
}
else {
mu[m] = -mu[i];
}
}
}
} LL G(int n) {
if(n <= MAXN) return preG[n];
LL ans = 0;
for(int d = 1;d * d * 2 <= n;d ++) {
int tmp = 0;
int d2 = d*d,m = n/d2;
for(int x = 1,lim = sqrt(n-d*d)/d;x*x <= m;x ++) {
while(lim*lim+x*x > m) lim --;
if((d*x)&1) tmp += lim / 2;
else tmp += lim;
}
ans += mu[d] * tmp;
}
return ans / 2;
} int main() {
// freopen("C.in","r",stdin);
preWork(MAXN);
int T = read();
while(T --) {
int n = read();
LL ans = 0;
for(int i = 1,r;i <= n;i = r + 1) {
r = n / (n / i);
ans += G(n / i) * (r-i+1);
}
printf("%lld\n",ans);
}
}
/**
3080075432
*/

D

题意:你要从 0 跳到 200,第 i 个位置能跳到第 i+1 和 i+2 上。你可以设置若干个传送门,一个位置只有一个入口,出口任意。跳到入口处就立马被传送到出口,如果构成环则永远出不去。求使得走到 200 的方案数恰好为 M 的一组传送门设置方案。 \(M < 2^{32}\)

key:构造

如果你想 ban 掉一个位置,那么一定是原地传送最优。考虑 ban 掉第 i 个位置,那么设第 i-1 个位置的方案数是 x,那么从第 i-1 开始的方案数是 \(x,0,x,x,2x\) 。这样就容易想到二进制。

如果想凑出 \(2^i\) ,那么应该设置为 \(2^i,X,2^i,2^i,2^{i+1},Y\) 。如果不想,那么应该是 \(2^i,2^i,2^{i+1},Y\) 。其中 X 是传到终点,Y 是原地传送。

#include<bits/stdc++.h>
#define ll long long
#define pa pair<int,int>
using namespace std;
ll m;
ll f[304];
vector<pa>ans;
int w33ha(){
ans.clear();
memset(f,0,sizeof(f));
f[0]=1;
f[1]=1;
//int a=0;
int B = 0;
for(ll i=0;i<=32;i++){
if((m&(1LL<<i))){
ans.push_back({B+1,199});
ans.push_back({B+5,B+5});
B += 6;
}
else{
ans.push_back({B+3,B+3});
B += 4;
}
}
ans.push_back({197,197});
ans.push_back({198,198});
printf("%d\n",ans.size());
for(int i=0;i<ans.size();i++){
printf("%d %d\n",ans[i].first,ans[i].second);
}
return 0;
} int main(){
while(scanf("%lld",&m)!=EOF)w33ha();
return 0;
}

E

F

题意:给一个有向图,定义 (u,v) 合法当且仅当 u 能走到 v,权值为 u^v。Q 次询问每次问第 k 大的权值。 \(n \le 5*10^4,m \le 2*10^5 , Q \le 10,T \le 3, k \le 10^9\)

key:bitset

容易想到二分答案,问题在于 check 。如果我们处理出来点 x 能走到哪些点,设这个集合是 S,那么就要找有多少个 \(y \in S\) ,使得 x^y>mid。这个是在 trie 上做的。所以就不用二分答案了,直接在 trie 上贪心。

考虑从 trie 上走的过程:贪心选 0,如果不行,那么走 1。判断是否不行是用子树和,这就是值域上的区间和,所以现在问题变成查询标号小于等于一个数的个数。

所以有一个 bitset 的做法。用 tarjan+拓扑排序 预处理 bitset 的复杂度是 \(O((n+m)n/W)\),模拟 trie 上的复杂度是 \(O(n^2/W\log n)\) ,后者应该是不行的。

所以手写 bitset ,对 n/W 位建一个前缀和。后者的复杂度为 \(O(n \log n)\) ,需要用到 __builtin_popcountll 。

所以这个题的总复杂度为 \(O(T((n+m)n/W+Qn\log n))\) ,空间复杂度为 \(O(n^2/W)\)

(这里手写了 bitset ,由于差分的性质所以改成前缀和,由于 __builtin_popcountll 而优化了查询的复杂度。如果不是二进制 1 的个数那么查询的复杂度要再乘一个 W,如果不满足差分性质可以在 bitset 上分块)

#include<bits/stdc++.h>
using namespace std; typedef unsigned long long ULL;
typedef long long LL;
typedef long double LD;
typedef pair<int,int> pii;
typedef pair<LL,int> pli;
const int SZ = 5e4 + 10;
const int INF = 1e9 + 10;
const int mod = 1e9 + 7;
const LD eps = 1e-8; LL read() {
LL n = 0;
char a = getchar();
bool flag = 0;
while(a > '9' || a < '0') { if(a == '-') flag = 1; a = getchar(); }
while(a <= '9' && a >= '0') { n = n * 10 + a - '0',a = getchar(); }
if(flag) n = -n;
return n;
} struct Bitset {
#define W (64) int n;
ULL bits[SZ / W + 10];
int num[SZ / W + 10]; void preWork() {
for(int i = 0;i <= n/W;i ++) num[i] = __builtin_popcountll(bits[i]);
for(int i = n/W-1;i >= 0;i --) num[i] += num[i+1];
// for(int i = 0;i < m;i ++) printf("%d ",sum[i]); puts("");
// for(int i = 0;i <= n/W;i ++) printf("%llu ",bits[i]); puts("");
} int ask(int x) {
if(x > n) return 0;
int blockid = x / W;
int ans = __builtin_popcountll(bits[blockid]>>(x%W));
blockid ++;
if(blockid <= n/W) ans += num[blockid];
return ans;
} int ask(int l,int r) {
return ask(l) - ask(r+1);
} void Or(const Bitset &t) {
for(int i = 0;i <= n / W;i ++) bits[i] |= t.bits[i];
} void Copy(const Bitset &t) {
n = t.n;
for(int i = 0;i <= n / W;i ++) bits[i] = t.bits[i];
} void Set(int x) {
bits[x/W] |= 1llu << (x%W);
} void init(int nn) {
n = nn; //n ++;
for(int i = 0;i <= n / W;i ++) bits[i] = 0;
} void print() {
for(int i = 0;i < n;i ++) {
if(bits[i/W] >> (i%W) & 1)
printf("%d ",i);
}
puts("");
} #undef W
}bs[SZ]; struct Tarjan { int n;
int dfn[SZ],low[SZ],dfs_clock,scccnt,sccnum[SZ];
vector<int> g[SZ],sccnodes[SZ];
stack<int> S; void dfs(int u) {
dfn[u] = low[u]= ++ dfs_clock;
S.push(u);
for(int v : g[u]) {
if(!dfn[v]) {
dfs(v);
low[u] = min(low[u],low[v]);
}
else if(!sccnum[v])
low[u] = min(low[u],dfn[v]);
}
if(low[u] == dfn[u]) {
scccnt ++;
while(1) {
int x = S.top(); S.pop();
sccnum[x] = scccnt;
sccnodes[scccnt].push_back(x);
if(x == u) break;
}
}
} vector<int> g2[SZ];
int cd[SZ]; void work(Bitset bs[]) {
for(int i = 1;i <= n;i ++)
if(!dfn[i])
dfs(i);
// for(int u = 1;u <= n;u ++) printf("%d ",sccnum[u]); puts("");
for(int u = 1;u <= n;u ++)
for(int v : g[u])
if(sccnum[u] != sccnum[v]) {
g2[sccnum[v]].push_back(sccnum[u]);
cd[sccnum[u]] ++;
}
static Bitset tmp[SZ];
for(int i = 1;i <= scccnt;i ++) {
tmp[i].init(n); //tmp[i].print();
for(int x : sccnodes[i])
tmp[i].Set(x);
}
queue<int> q;
for(int i = 1;i <= scccnt;i ++)
if(cd[i] == 0) {
q.push(i);
}
while(q.size()) {
int v = q.front(); q.pop();
// printf("%d: ",v); tmp[v].print();
for(int x : sccnodes[v]) bs[x].Copy(tmp[v]);
for(int u : g2[v]) {
tmp[u].Or(tmp[v]);
cd[u] --;
if(cd[u] == 0) {
q.push(u);
}
}
}
} void addEdge(int x,int y) {
g[x].push_back(y);
} void init(int nn) {
n = nn;
for(int i = 1;i <= scccnt;i ++) {
g2[i].clear();
sccnodes[i].clear();
cd[i] = 0;
}
for(int i = 1;i <= n;i ++) {
g[i].clear();
dfn[i] = low[i] = sccnum[i] = 0;
}
scccnt = 0;
dfs_clock = 0;
} }tarjan; int now[SZ]; void work(int n,int &mid,int id,int &k) {
LL ans = 0;
for(int i = 1;i <= n;i ++) {
int t,l,r;
if(i>>id&1)
t = bs[i].ask(l=now[i],r=now[i]+(1<<id)-1);
else
t = bs[i].ask(l=now[i]+(1<<id),r=now[i]+(2<<id)-1);
ans += t;
// printf("%d: [%d,%d] %d\n",i,l,r,t);
}
//cout << id << " " << ans << " " << k << endl;
if(k <= ans) {
for(int i = 1;i <= n;i ++) {
if((i>>id&1) == 0) {
now[i] |= 1 << id;
}
}
mid |= 1 << id;
}
else {
k -= ans;
for(int i = 1;i <= n;i ++) {
if(i>>id&1) {
now[i] |= 1 << id;
}
}
}
//cout << k << endl;
// for(int i = 1;i <= n;i ++) printf("%d ",now[i]); puts("");
} int main() {
// freopen("F.in","r",stdin); freopen("my.out","w",stdout);
int T = read();
while(T --) {
int n = read(),m = read(),Q = read();
tarjan.init(n);
for(int i = 1;i <= m;i ++) {
int x = read(),y = read();
tarjan.addEdge(x,y);
}
tarjan.work(bs);
// for(int i = 1;i <= n;i ++) bs[i].print();
for(int i = 1;i <= n;i ++){
bs[i].preWork();
}
while(Q --) {
int k = read();
int ans = 0;
for(int i = 1;i <= n;i ++) now[i] = 0;
for(int i = 16;i >= 0;i --) {
work(n,ans,i,k);
}
printf("%d\n",ans);
}
}
}

G

题意:给一个 n 次多项式 F,求一个 n 阶多项式 G,使得 G 的每一个根(不一定实根)为 F 的对应根的 m 次幂。 \(n+m \le 10,|a_i| \le 120\),保证 G 的系数 \(< 10^{12}\)

key:牛顿恒等式

设多项式 \(F(x)=\sum_{0\le i \le n} a_ix^i\) ,设其所有根为 \(x_1,x_2...x_n\) (包括复根) ,设 \(S_k=\sum_{i=1}^nx_i^k\) ,\(b_i=a_{n-i}\) 。则对于任意的正整数 k ,有

\[\sum_{i=1}^kS_ib_{k-i}+k\times b_k=0
\]

所以只要用系数递推出 n*m 个 S,然后反推出答案即可。因为 \(SG_i=SF_{i \cdot m}\) 。

#include<bits/stdc++.h>
using namespace std; typedef long long LL;
typedef long double LD;
typedef pair<int,int> pii;
typedef pair<LL,int> pli;
const int SZ = 1e5 + 10;
const int INF = 1e9 + 10;
const int mod = 1e9 + 7;
const LD eps = 1e-8; LL read() {
LL n = 0;
char a = getchar();
bool flag = 0;
while(a > '9' || a < '0') { if(a == '-') flag = 1; a = getchar(); }
while(a <= '9' && a >= '0') { n = n * 10 + a - '0',a = getchar(); }
if(flag) n = -n;
return n;
} LL a[111],b[111],s[111]; int main() {
int n,m;
while(~scanf("%d%d",&n,&m) && n && m) {
memset(a,0,sizeof a);
memset(b,0,sizeof b);
memset(s,0,sizeof s);
for(int i = 0;i < n;i ++) a[i] = read(); a[n] = 1;
reverse(a,a+n+1);
for(int k = 1;k <= n*m;k ++) {
s[k] = -k*a[k];
for(int i = 1;i < k;i ++) s[k] -= s[i] * a[k-i];
}
b[0] = 1;
for(int k = 1;k <= n;k ++) {
b[k] = 0;
for(int i = 1;i <= k;i ++) b[k] -= s[i*m] * b[k-i];
b[k] /= k;
}
for(int i = n;i >= 1;i --) {
printf("%lld%c",b[i],i==1?'\n':' ');
}
}
}

H

题意:定义字符串 A 几乎匹配 B 当且仅当 B 存在一个子串,与 A 长度相同且至多一个字符不同。给出 A,求有多少个长度为 m 的 B。字符集是 {0,1}。 \(|A|,m\le 40\)

key:dp

主要怕算重,这个只需要找到第一次匹配的位置即可。\(f_{i,j}\) 表示 A 第一次出现位置在 \([i-|A|+1,i]\) 且第 j 位不同的方案数,有:

\[f_{i,j} = 2^{i-|A|}-\sum_{k\le i-|A|,l}f_{k,l}\times 2^{i-|A|-k}-\sum_{i-|A|< k< i}f_{k,l}\times w(i,j,k,l)
\]

即前面随便填的,减去出现过的。第一项是出现位置与当前串不相交的个数,第二项是相交的个数。注意这里相交可能不合法,所以需要一个 \(w(i,j,k,l)\) 来 check,合法时返回 1,否则返回 0。这个可以预处理一下。总复杂度是 \(O(m^2|A|^2)\)

#include<bits/stdc++.h>
using namespace std; typedef long long LL;
typedef long double LD;
typedef pair<int,int> pii;
typedef pair<LL,int> pli;
const int SZ = 1e5 + 10;
const int INF = 1e9 + 10;
const int mod = 1e9 + 7;
const LD eps = 1e-8; LL read() {
LL n = 0;
char a = getchar();
bool flag = 0;
while(a > '9' || a < '0') { if(a == '-') flag = 1; a = getchar(); }
while(a <= '9' && a >= '0') { n = n * 10 + a - '0',a = getchar(); }
if(flag) n = -n;
return n;
} char s[55];
int n,m;
LL f[55][55];
LL g[55][55][55]; bool isequ(int len,int p1,int p2) {
string s1,s2;
for(int i = 1;i <= len;i ++) {
if(i==p1) {
if(s[i] == '0') s1 += '1';
else s1 += '0';
}
else s1 += s[i];
}
for(int i = n-len+1;i <= n;i ++) {
if(i==p2) {
if(s[i] == '0') s2 += '1';
else s2 += '0';
}
else s2 += s[i];
}
return s1 == s2;
} int main() {
int T = read();
while(T --) {
n = read(),m = read();
scanf("%s",s+1);
for(int j = 0;j <= n;j ++) {
for(int k = 1;k < n;k ++) {
for(int l = 0;l <= n;l ++) {
if(isequ(k,j,l)) {
g[j][k][l] = 1;
}
else {
g[j][k][l] = 0;
}
}
}
}
for(int i = 1;i <= m;i ++) {
for(int j = 0;j <= n;j ++) {
if(i-n < 0) {
f[i][j] = 0;
continue;
}
LL ans = 1ll<<(i-n);
for(int k = 1;k < i;k ++) {
for(int l = 0;l <= n;l ++) {
if(k <= i-n) {
ans -= f[k][l] * (1ll<<(i-n-k));
}
else {
ans -= f[k][l] * g[j][k-i+n][l];
}
}
}
f[i][j] = ans;
}
}
LL ans = 0;
for(int i = 1;i <= m;i ++) {
for(int j = 0;j <= n;j ++) {
ans += f[i][j] * (1ll<<(m-i));
}
}
printf("%lld\n",ans);
}
}

I

打表找规律

J

题意:二维平面上给出 n 个点,求所有锐角三角形面积之和。 \(n \le 2000\)

key:扫描线

总面积减去直角三角形面积减去钝角三角形面积。这三个都能在极角排序的序列上用双指针定位。算面积用前缀和就行。

#include<bits/stdc++.h>
using namespace std; typedef __int128 int128;
typedef long long LL;
typedef long double LD;
typedef pair<int,int> pii;
typedef pair<LL,int> pli;
const int SZ = 1e6 + 10;
const int INF = 1e9 + 10;
const int mod = 998244353;
const LD eps = 1e-14;
const LD PI = acos(-1); LL read() {
LL n = 0;
char a = getchar();
bool flag = 0;
while(a > '9' || a < '0') { if(a == '-') flag = 1; a = getchar(); }
while(a <= '9' && a >= '0') { n = n * 10 + a - '0',a = getchar(); }
if(flag) n = -n;
return n;
} LL ksm(LL a,LL b) {
LL ans = 1;
while(b) {
if(b&1) ans = a * ans % mod;
a = a * a % mod;
b >>= 1;
}
return ans;
} struct Point {
LL x,y;
LL vx,vy;
Point(LL _x=0,LL _y=0,LL _vx=0,LL _vy=0):x(_x),y(_y),vx(_vx),vy(_vy) { }
Point operator -(Point &o) { return Point(x-o.x,y-o.y); }
Point operator +(Point &o) { return Point(x+o.x,y+o.y); }
Point getV() { return Point(vx,vy); }
}a[SZ],b[SZ],sb[SZ]; int128 operator ^(Point &a,Point &o) { return (int128)a.x*o.y-(int128)a.y*o.x; }
int128 operator *(Point &a,Point &o) { return (int128)a.x*o.x+(int128)a.y*o.y; } int getxx(Point a) {
if(a.x>0 && a.y>=0) return 1;
if(a.x<=0 && a.y>0) return 2;
if(a.x<0 && a.y<=0) return 3;
if(a.x>=0 && a.y<0) return 4;
} bool operator <(Point &a,Point &b) {
if(getxx(a)!=getxx(b)) return getxx(a) < getxx(b);
return (int128)a.x*b.y>(int128)a.y*b.x;
} bool isSameAlpha(Point &a,Point &b) {
if(getxx(a) != getxx(b)) return false;
return (a^b) == 0;
} int main() {
// freopen("J.in","r",stdin); freopen("2.out","w",stdout);
int T = read();
while(T --) {
int n = read();
for(int i = 1;i <= n;i ++) {
a[i].x = read();
a[i].y = read();
} LL ans = 0;
LL sjx = 0,zjsjx = 0,djsjx = 0;
for(int o = 1;o <= n;o ++) {
int len = 0;
for(int i = 1;i <= n;i ++) {
if(i == o) continue;
b[++ len] = a[i] - a[o];
b[len].vx = b[len].x % mod;
b[len].vy = b[len].y % mod;
b[++ len] = a[o] - a[i];
}
sort(b+1,b+1+len); int tot = 0;
for(int i = 1,j = 1;i <= len;i ++) {
if(i == len || !isSameAlpha(b[i],b[i+1])) {
Point ans = b[j]; j++;
while(j<=i) {
ans.vx = (ans.vx + b[j].vx) % mod;
ans.vy = (ans.vy + b[j].vy) % mod;
j ++;
}
b[++ tot] = ans;
}
}
len = tot;
for(int i = 1;i <= len;i ++) {
b[i+len].x = b[i].x;
b[i+len].y = b[i].y;
b[i+len].vx = b[i].vx;
b[i+len].vy = b[i].vy;
}
len*=2;
sb[1] = Point(b[1].vx,b[1].vy);
for(int i = 2;i <= len;i ++) {
sb[i].x = (sb[i-1].x + b[i].vx) % mod;
sb[i].y = (sb[i-1].y + b[i].vy) % mod;
} /* printf("%d\n",o);
for(int i = 1;i <= len;i ++) {
printf("(%3lld,%3lld) (%3lld,%3lld)\n",b[i].x,b[i].y,b[i].vx,b[i].vy);
//printf("(%lld,%lld)\n",b[i].vx,b[i].vy);
}*/
// for(int i = 1;i <= len;i ++) printf("(%lld,%lld)\n",sb[i].x,sb[i].y); int r3 = 1,r2 = 1;
LL t1 = 0,t2 = 0,t3 = 0;
for(int i = 1;i <= len/2;i ++) {
Point now = b[i].getV();
// if(now.x == 0 && now.y == 0) continue;
while(r2<=len&&b[i]*b[r2]>0) r2++;
while(r3+1<=len&&(b[i]^b[r3+1])>0) r3++;
Point b1 = (sb[r3] - sb[i]);
Point b2 = (sb[r3] - sb[r2 - 1]);
(t1 += (now ^ b1) % mod) %= mod;
(t3 += (now ^ b2) % mod) %= mod;
// printf("%d %d %d %d %lld\n",i,r1,r2,r3);
}
// printf("-%d %lld %lld %lld\n",o,t1,t2,t3);
(sjx += t1) %= mod;
(zjsjx += t2) %= mod;
(djsjx += t3) %= mod;
}
//printf("%lld %lld %lld\n",sjx,zjsjx,djsjx);
(ans += sjx * ksm(3,mod-2) % mod - zjsjx - djsjx) %= mod;
ans += mod; ans %= mod; printf("%lld\n",ans);
}
} /**
5
5 4
2 4
3 5
3 1 7
0 0
0 1
0 -1
1 0
2 0
-1 0
-2 0 */

ACM-ICPC Asia Beijing Regional Contest 2018 Reproduction hihocoder1870~1879的更多相关文章

  1. hihoCoder #1871 : Heshen's Account Book-字符串暴力模拟 自闭(getline()函数) (ACM-ICPC Asia Beijing Regional Contest 2018 Reproduction B) 2018 ICPC 北京区域赛现场赛B

    P2 : Heshen's Account Book Time Limit:1000ms Case Time Limit:1000ms Memory Limit:512MB Description H ...

  2. hihoCoder #1870 : Jin Yong’s Wukong Ranking List-闭包传递(递归) (ACM-ICPC Asia Beijing Regional Contest 2018 Reproduction A) 2018 ICPC 北京区域赛现场赛A

    P1 : Jin Yong’s Wukong Ranking List Time Limit:1000ms Case Time Limit:1000ms Memory Limit:512MB Desc ...

  3. 2018-2019, ICPC, Asia Yokohama Regional Contest 2018 K

    传送门:https://codeforces.com/gym/102082/attachments 题解: 代码: /** * ┏┓ ┏┓ * ┏┛┗━━━━━━━┛┗━━━┓ * ┃ ┃ * ┃ ━ ...

  4. 2018 ACM-ICPC Asia Beijing Regional Contest (部分题解)

    摘要 本文主要给出了2018 ACM-ICPC Asia Beijing Regional Contest的部分题解,意即熟悉区域赛题型,保持比赛感觉. Jin Yong’s Wukong Ranki ...

  5. ACM ICPC Central Europe Regional Contest 2013 Jagiellonian University Kraków

    ACM ICPC Central Europe Regional Contest 2013 Jagiellonian University Kraków Problem A: Rubik’s Rect ...

  6. 2019-2020 ICPC, Asia Jakarta Regional Contest (Online Mirror, ICPC Rules, Teams Preferred)

    2019-2020 ICPC, Asia Jakarta Regional Contest (Online Mirror, ICPC Rules, Teams Preferred) easy: ACE ...

  7. The 2018 ACM-ICPC Asia Beijing Regional Contest

    http://hihocoder.com/problemset/problem/ #1870 : Jin Yong’s Wukong Ranking List 我是每加1个点就dfs判断1次. 正解是 ...

  8. 2018 ICPC Asia Jakarta Regional Contest

    题目传送门 题号 A B C D E F G H I J K L 状态 Ο . . Ο . . Ø Ø Ø Ø . Ο Ο:当场 Ø:已补 .  :  待补 A. Edit Distance Thin ...

  9. Gym - 101981K The 2018 ICPC Asia Nanjing Regional Contest K.Kangaroo Puzzle 暴力或随机

    题面 题意:给你1个20*20的格子图,有的是障碍有的是怪,你可以每次指定上下左右的方向,然后所有怪都会向那个方向走, 如果2个怪撞上了,就融合在一起,让你给不超过5w步,让所有怪都融合 题解:我们可 ...

随机推荐

  1. [ACTF2020 新生赛]Exec

    0x00 知识点 命令执行 这里见了太多了..以前也写过: https://www.cnblogs.com/wangtanzhi/p/12246386.html 命令执行的方法大抵是加上管道符或者分号 ...

  2. 【Android】家庭记账本手机版开发报告三

    一.说在前面 昨天 对第一天的框架结构进行了四方面的完善 今天 对界面显示和逻辑结构进行完善 问题 无 二.界面展示完善 1.使用可回收的列表recyclerView展示账单的信息,并设置数据项为卡片 ...

  3. HDU - 4430 Yukari's Birthday(二分+枚举)

    题意:已知有n个蜡烛,过生日在蛋糕上摆蜡烛,将蜡烛围成同心圆,每圈个数为ki,蛋糕中心最多可摆一个蜡烛,求圈数r和看,条件为r*k尽可能小的情况下,r尽可能小. 分析:n最大为1012,k最少为2,假 ...

  4. POJ 1185:炮兵阵地

    炮兵阵地 Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 21366   Accepted: 8280 Description ...

  5. 轻量级UILabel分段点击扩展更新啦

    http://www.code4app.com/thread-31445-1-1.html Tag: 项目介绍: YBAttributeTextTapAction 一行代码添加文本点击事件 效果图 S ...

  6. jQuery课上笔记19.5.17

    jQuery 选择器 $("*"):所有元素 $("#idname"):id="idname"的元素 $(".classname& ...

  7. c# 数据库操作,多数据库操作、数据库操作异常报错等问题

    1.引入相关的命名空间 在C#中要操作数据库,一般情况需要引入两个命名空间,在三种连接模式中都要引入下面的命名空间: System.Data;描述与数据源连接的当前状态. // // 摘要: // 连 ...

  8. pycharm和python安装

    1.pycharm安装:https://www.cnblogs.com/dcpeng/p/9031405.html 2,python安装:https://www.liaoxuefeng.com/wik ...

  9. HDU - 1068 Girls and Boys(二分匹配---最大独立集)

    题意:给出每个学生的标号及与其有缘分成为情侣的人的标号,求一个最大集合,集合中任意两个人都没有缘分成为情侣. 分析: 1.若两人有缘分,则可以连一条边,本题是求一个最大集合,集合中任意两点都不相连,即 ...

  10. Python说文解字_Python之多任务_03

    问:线程学完了,现在我们开始学习进程了吧? 答:是的.前面说到线程就是我们的手,我们现在可以学习一下我们的“胳膊”了. 我们有了多线程,为什么还要学习多进程呢?这是因为在Python当中有一把GIL锁 ...