CCPC-Winter Camp div2 day5
DIV2
有部分div1的题会写
div1的大佬真的太强了
向他们学习
(好像和zqc大佬说过话了hhh,zqc大佬真的是一个超有意思的人啊,羡慕有妹子队友的zqc大佬)
A:
你有一棵树,你想把它画在平面上,使得没有边相交。
题解:dfs(u,dep)表示我在第dep层,第cnt[dep]列来放置第u个节点
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+;
int n,m;
struct EDGE{
int v,nxt;
}edge[maxn];
int head[maxn];
int tot=;
void add_edge(int u,int v){
edge[tot].v=v;
edge[tot].nxt=head[u];
head[u]=tot++;
}
int cnt[maxn];
int vis[maxn];
struct node{
int x,y;
}ans[maxn]; void dfs(int u,int dep){
for(int i=head[u];i!=-;i=edge[i].nxt){
int v=edge[i].v;
if(!vis[v]){
vis[v]=;
ans[v].x=dep;
ans[v].y=cnt[dep];
cnt[dep]++;
dfs(v,dep-);
}
}
}
int main(){ memset(head,-,sizeof(head));
tot=;
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++){
int u,v;
scanf("%d%d",&u,&v);
add_edge(u,v);
add_edge(v,u);
}
for(int i=;i<=n;i++){
cnt[i]=;
vis[i]=;
}
dfs(,n);
for(int i=;i<=n;i++){
printf("%d %d\n",ans[i].x,ans[i].y);
}
}
B:
所有n个节点有标号的无根树,直径为0,1,…,n−1的树有多少个。
由于答案很大,对mod取模。
学了一点新知识:purfer序列又和其他神奇的序列一样,我都不会QAQ(晚风为什么这么凉,教练我想学数学
purfer序列是用来对无根数计数的 ,(大概是无根树的同构balabala的太多了,然后某神奇的科学家就给整出这个序列了)
日后补这个知识点(flag立下了
C:
你有一个数列。你可以进行这样的一次操作,每次选择数列中其中一个数然后将其除2下取整。请问对这些数字进行不超过kk次操作,这些数字的总和最小值可能是多少。’
div2的n只有1e3,虽然说k是1e9,但是非常显然对于每一个ai都最多操作30次即可,复杂度是30*nlogn
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + ;
int a[maxn];
priority_queue<int> q;
int n, k;
int main() {
scanf("%d%d", &n, &k);
for(int i = ; i <= n; i++) {
scanf("%d", &a[i]);
q.push(a[i]);
}
while(k--) {
if(q.top() / == ) break;
int x = q.top();
q.pop();
q.push(x / );
}
long long ans = ;
while(!q.empty()) {
ans += q.top();
q.pop();
}
cout << ans << endl;
}
div1的版本有点难,最主要的是他是询问这个区间内进行k 次操作后最小的区间和
这些天camp学到一个知识点叫做拆分,就是把一个数用二进制分组的形式表示,这样一个数最多就可以被表示成log(ai)个数,我们预处理出这n个数拆出来的数,即n*log(n)个数,用主席数维护区间前k大数,所以每次询问得到这个区间前k大和,用区间和减去即可得到k次操作后最小的区间和
但是!!!重点来了,我们计算一下空间复杂度。n*log(a[i])*log(segma(log(a[i]))),被256M卡成弟弟的空间复杂度,所以你没了
不过可爱的dls小姐姐告诉我们,
emmm貌似是用重构主席树,然后离线操作,这样复杂度就被滚了一个log下去
代码如下
#include <set>
#include <map>
#include <deque>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <bitset>
#include <cstdio>
#include <string>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std; typedef long long LL;
typedef pair<LL, LL> pLL;
typedef pair<LL, int> pLi;
typedef pair<int, LL> pil;;
typedef pair<int, int> pii;
typedef unsigned long long uLL;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define bug printf("*********\n")
#define FIN freopen("input.txt","r",stdin);
#define FON freopen("output.txt","w+",stdout);
#define IO ios::sync_with_stdio(false),cin.tie(0)
#define debug1(x) cout<<"["<<#x<<" "<<(x)<<"]\n"
#define debug2(x,y) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<"]\n"
#define debug3(x,y,z) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<" "<<#z<<" "<<z<<"]\n" const double eps = 1e-;
const int mod = ;
const int maxn = 2e5 + ;
const double pi = acos(-);
const int INF = 0x3f3f3f3f;
const LL INFLL = 0x3f3f3f3f3f3f3f3f;
struct TREE {
int ls, rs, s;
LL sum;
} T[maxn << ];
int tot = ;
struct QUERY {
int l, r, k;
LL ans;
} q[maxn << ];
LL read() {
int x = , f = ; char ch = getchar();
while(ch < '' || ch > '') {
if(ch == '-')f = -;
ch = getchar();
}
while(ch >= '' && ch <= '') {
x = x * + ch - '';
ch = getchar();
}
return x * f;
} void push_up(int rt) {
int ls = T[rt].ls;
int rs = T[rt].rs;
T[rt].s = T[ls].s + T[rs].s;
T[rt].sum = T[ls].sum + T[rs].sum;
return;
}
void update(int l, int r, int &rt, int pre, int x) {
rt = ++tot;
T[rt] = T[pre];
if(l == r) {
T[rt].s++;
T[rt].sum += (x - (x >> ));
return;
}
int mid = (l + r) >> ;
if(x <= mid) update(l, mid, T[rt].ls, T[pre].ls, x);
else update(mid + , r, T[rt].rs, T[pre].rs, x);
push_up(rt);
}
LL query(int l, int r, int rt, int pre, int k) {
if(l == r) return (LL)(k * (l - (l >> )));
int ls = T[rt].ls;
int rs = T[rt].rs;
int Ls = T[pre].ls;
int Rs = T[pre].rs;
int mid = (l + r) >> ;
LL ans = ;
if(k > T[rs].s - T[Rs].s) {
ans += T[rs].sum - T[Rs].sum;
ans += query(l, mid, ls, Ls, k - (T[rs].s - T[Rs].s)) ;
} else {
ans += query(mid + , r, rs, Rs, k);
}
return ans;
}
LL sum[maxn];
int root[maxn];
LL a[maxn];
int num[maxn];
int main() {
#ifndef ONLINE_JUDGE
FIN
#endif
int n, m;
sum[] = ;
scanf("%d%d", &n, &m);
for(int i = ; i <= n; i++) {
a[i] = read();
sum[i] = sum[i - ] + a[i];
} for(int i = ; i <= m; i++) {
q[i].l = read();
q[i].r = read();
q[i].k = read();
q[i].ans = sum[q[i].r] - sum[--q[i].l];
} for (int i = ; i >= ; --i) {
int L = << i, R = << i;
//二进制分组
tot = ;//重构
for (int j = ; j <= n; ++j) {
if ((a[j] >> i) & ) {
update(L, R, root[j], root[j - ], a[j]);
sum[j] = sum[j - ] + a[j] - (a[j] >> );
num[j] = num[j - ] + ;
} else {
root[j] = root[j - ];
sum[j] = sum[j - ];
num[j] = num[j - ];
}
}
for (int j = ; j <= m; ++j) {
if (q[j].k && q[j].k >= num[q[j].r] - num[q[j].l]) {
q[j].k -= num[q[j].r] - num[q[j].l];
q[j].ans -= sum[q[j].r] - sum[q[j].l];
} else {
q[j].ans -= query(L, R, root[q[j].r], root[q[j].l], q[j].k);
q[j].k = ;
}
}
for (int j = ; j <= n; ++j) if ((a[j] >> i) & ) a[j] >>= ;
}
for(int i = ; i <= m; i++) {
printf("%lld\n", q[i].ans);
}
return ;
}
D:
你有一个n*n的矩阵,一开始都是空的,你要在其中填入1到n−2的数字和字符X。
要求每行每列中1到n-2中的每个数都恰好出现了一次,并且恰好有两个字符X。
同时对于第i行,要求两个X之间的数字之和为ri,第i列,要求两个X之间的数字之和为ci。
n小于7
大搜索,把所有情况搜出来即可
剪枝1:由于每行每列的和是有限制的,我们维护一个第i行的和sum1和第j列的和sun2,如果sum1、sum2大于这个限制,直接return 即可,(要考虑X是否放了两个的情况)
剪枝2:预处理出加到每行的和可以用哪些数得到,还有每列的和可以用哪些数得到,然后用这些数去枚举暴力,就可以跑出答案(听说dls0ms过了,神仙)
自己没有补(flag++)
队友代码:
#include<bits/stdc++.h>
#define fi first
#define se second
#define iis std::ios::sync_with_stdio(false)
#define pb push_back
#define o2(x) (x)*(x)
using namespace std;
typedef long long LL;
typedef pair<int, LL> pii;
const int MXN = 2e6 + ;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + ;
int n;
int vis[][];
int visr[][];
int visc[][];
int needr[];
int needc[];
int nowrx[],nowcx[];// di i 行 第一个x的纵坐标 竖 横坐标
int haverx[],havecx[];
int nowc[],nowr[];
int totc[],totr[];
int flag = ;
int sum;
bool check() {
for(int i=; i<=n; i++) {
if(havecx[i]!= || haverx[i]!=) {
return ;
}
}
return ;
}
void dfs(int x,int y) {
//cout<<"now:"<<x<<","<<y<<",,"<<flag<<endl;
if(haverx[x]== && sum-totr[x]<needr[x]) return;
if(havecx[y]== && sum-totc[y]<needc[y]) return;
if(flag ) return ;
if(x==n+) {
if(check())
flag = ;
//cout<<"haha:"<<flag<<endl;
for(int i=; i<=n; i++) {
for(int j=; j<=n; j++) {
if(vis[i][j]!=-) {
printf("%d",vis[i][j]);
} else {
printf("X");
}
}
puts("");
}
return ;
}
// for(int i=1; i<=n; i++) {
// for(int j=1; j<=n; j++) {
// if(vis[i][j]!=-1) {
// printf("%d",vis[i][j]);
// } else {
// printf("X");
// }
// }
// puts("");
// }
// 判断是否可放x
if(haverx[x]== &&havecx[y]==) {
nowrx[x]=y;
nowcx[y]=x;
havecx[y]++;
haverx[x]++;
vis[x][y]=-;
if(y+>n) {
if(haverx[x]==)
dfs(x+,);
} else {
dfs(x,y+);
}
vis[x][y]=;
nowrx[x]=;
nowcx[y]=;
havecx[y]--;
haverx[x]--;
}
// 横有了一个x 竖没有x
else if(haverx[x]== && havecx[y]==) {
int cnt = nowr[x];//getnum(nowrx[x],y,x,1);
//cout<<"cnt:"<<cnt<<endl;
// 第 i 行 两个x之间的属的和满足ri
if(cnt==needr[x]) {
havecx[y]++;
haverx[x]++;
nowcx[y]=x;
vis[x][y]=-;
if(y+>n) {
if(haverx[x]==)
dfs(x+,);
} else {
dfs(x,y+);
}
vis[x][y]=;
havecx[y]--;
haverx[x]--;
nowcx[y]=;
}
}
// 竖有了一个x 横没有x
else if(haverx[x]== && havecx[y]==) {
int cnt = nowc[y];//getnum(nowcx[y],x,y,0);
// 第 i 行 两个x之间的属的和满足ri
if(cnt==needc[y]) {
havecx[y]++;
haverx[x]++;
nowrx[x]=y;
vis[x][y]=-;
if(y+>n) {
if(haverx[x]==)
dfs(x+,);
} else {
dfs(x,y+);
}
vis[x][y]=;
havecx[y]--;
haverx[x]--;
nowrx[x]=;
}
}// 横竖都有一个
else {
int cnt1 = nowr[x];//getnum(nowrx[x],y,x,1);
int cnt2 = nowc[y];//getnum(nowcx[y],x,y,0);
if(cnt1 == needr[x] && cnt2 == needc[y]) {
havecx[y]++;
haverx[x]++;
vis[x][y]=-;
if(y+>n) {
if(haverx[x]==)
dfs(x+,);
} else {
dfs(x,y+);
}
vis[x][y]=;
havecx[y]--;
haverx[x]--;
}
}
for(int i=; i<=n-; i++) {
int cnt1 = ;
if(haverx[x]==) {
cnt1 =nowr[x];//getnum(nowrx[x],y,x,1); if(cnt1+i>needr[x]) continue;
//cout<<"cnt1+i:"<<cnt1+i<<"vs"<<needr[x]<<endl;
}
int cnt2 = ;
if(havecx[y]==) {
cnt2 = nowc[y];//getnum(nowcx[y],x,y,0);
if(cnt2+i>needc[y]) continue;
}
if(visc[y][i]== && visr[x][i]== ) {
visc[y][i]=;
visr[x][i]=;
vis[x][y]=i;
totc[y]+=i;
totr[x]+=i;
if(haverx[x]==) {
nowr[x]+=i;
}
if(havecx[y]==) {
nowc[y]+=i;
}
if(y+>n) {
if(haverx[x]==)
dfs(x+,);
} else {
dfs(x,y+);
}
if(haverx[x]==) {
nowr[x]-=i;
}
if(havecx[y]==) {
nowc[y]-=i;
}
totc[y]-=i;
totr[x]-=i;
visc[y][i]=;
visr[x][i]=;
vis[x][y]=;
}
}
}
void init() {
flag = ;
memset(vis,,sizeof vis);
memset(visr,,sizeof visr);
memset(visc,,sizeof visc);
memset(needr,,sizeof needr);
memset(needc,,sizeof needc);
memset(nowrx,,sizeof nowrx);
memset(nowcx,,sizeof nowcx);
memset(haverx,,sizeof haverx);
memset(havecx,,sizeof havecx);
memset(nowc,,sizeof nowc);
memset(nowr,,sizeof nowr);
memset(totc,,sizeof totc);
memset(totr,,sizeof totr);
sum=;
for(int i=; i<=n-; i++) {
sum+=i;
}
// cout<<sum<<endl;
}
int main() {
int T;
scanf("%d",&T);
while(T--) { scanf("%d",&n);
init();
for(int i=; i<=n; i++) {
scanf("%d",&needr[i]);
}
for(int j=; j<=n; j++) {
scanf("%d",&needc[j]);
}
dfs(,);
if(T)
puts("");
}
}
E:(待补)
F:
n<=15非常明显的状压dp
状压dp计数,定义状态为dp[i][j][k] ,长度为i到最后一个数是j的状态k的排列的数量
枚举时判断一下如果这个数放进去是否符合题目的序列即可
最后的答案就是长度为n的序列结尾数从1~n,状态为(1<<n)-1 时的和
#include<bits/stdc++.h>
using namespace std;
const int mod = 1e9 + ;
int n;
char str[];
int dp[][][ << ]; //长度为i,结尾是j,状态是k
int main() {
memset(dp, , sizeof(dp));
scanf("%d %s", &n, str + );
for(int i = ; i <= n; i++) {
dp[][i][( << i - )] = ;
}
for(int i = ; i < n; i++) {
for(int j = ; j <= n; j++) {
for(int k = ; k <= n; k++) {
if(j != k) {
int flag = ;
if(((j % k == && j / k == ) || (k % j == && k / j == )) ) {
if(str[i] == '') {
flag = ;
}
} else {
if(str[i] == '') {
flag = ;
}
}
//cout<<flag<<endl;
if(flag) {
for(int p = ; p < ( << n); p++) {
if((p & ( << k - )) == ) {
dp[i + ][k][p | ( << k - )] = (dp[i + ][k][p | ( << k - )] + dp[i][j][p]) % mod;
}
}
}
}
}
}
}
int ans = ;
for (int i = ; i <= n; i++)
ans = (ans + dp[n][i][( << n) - ]) % mod;
cout << ans << endl;
}
G:
数论知识,待补(目测不可做)(真的不可做)(不补了告辞)(可以留着祸害学弟)(去py一下标程)
H:
题意:
div1是非常不快乐的树链剖分,div2是非常快乐的dfs
注意建图,因为最多复制m边,那么最多也就只有1e6条边,直接建就行,然后dfs计数,点对之间的距离就是左侧树的大小*右侧树的大小,算贡献
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + ;
const int mod = 1e9 + ;
struct EDGE {
int v, nxt;
} edge[maxn << ];
int head[maxn];
int tot;
void add_edge(int u, int v) {
edge[tot].v = v;
edge[tot].nxt = head[u];
head[u] = tot++;
}
long long ans = ;
long long sz[maxn];
int n, m, u, v, a, b;
void dfs(int u, int pre) {
sz[u] = ;
for(int i = head[u]; i != -; i = edge[i].nxt) {
int v = edge[i].v;
if(v == pre) continue;
dfs(v, u);
sz[u] += sz[v];ji
ans = (ans % mod + (long long)sz[v] * (n * m - sz[v]) % mod) % mod;
}
}
int main() {
memset(head, -, sizeof(head));
tot = ;
scanf("%d%d", &n, &m);
for(int i = ; i < n; i++) {
scanf("%d%d", &u, &v);
for(int j = ; j < m; j++) {
add_edge(u + j * n, v + j * n);
add_edge(v + j * n, u + j * n);
}
}
for(int i = ; i < m; i++) {
scanf("%d%d%d%d", &a, &b, &u, &v);
add_edge(u + (a - ) * n, v + (b - ) * n);
add_edge(v + (b - ) * n, u + (a - ) * n);
}
dfs(, );
cout << ans << endl;
}
I:
题意:
比赛最后开的这题,口胡了一大半,但是没有写出来,,,码力太差QAQ
实际上真正写还是差一点的
后来可爱的dls讲了之后再加上学长的帮助后终于会写了(感谢帅气的学长(舔狗舔到最后应有尽有
题解:我们注意到x实际上是不变的,那么,我们每个数无论是怎么根据x排序,他的相对位置是不变的,这样我们就可以用前缀和来维护这个区间和
注意大小关系,那么我们定义一个标记,如果这个数字小于等于x,那么这个数所在的位置的标记为0,否则为1,那么我们只需要用线段树维护区间内0和1的个数
每次操作2的时候,我们只需要统计这个区间内0的个数,将区间(l,l+cnt0-1)给直接覆盖为0,剩下的(l+cnt0,r)覆盖为1
每次操作3的时候,我们同理,统计区间内1的个数,然后覆盖即可
每次操作1的时候,我们分别统计区间(1,l-1)(1,r)内0和1的个数,因为每个数字的相对位置是不变的,所以前缀和的相对位置也是不变的,直接减一减就行,具体看代码就懂啦
代码:
#include <set>
#include <map>
#include <deque>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <bitset>
#include <cstdio>
#include <string>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std; typedef long long LL;
typedef pair<LL, LL> pLL;
typedef pair<LL, int> pLi;
typedef pair<int, LL> pil;;
typedef pair<int, int> pii;
typedef unsigned long long uLL; #define bug printf("*********\n")
#define debug(x) cout<<#x"=["<<x<<"]" <<endl
#define FIN freopen("input.txt","r",stdin);
#define IO ios::sync_with_stdio(false),cin.tie(0)
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
const double eps = 1e-;
const int mod = ;
const int maxn = 2e5 + ;
const double pi = acos(-);
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3fLL;
int sum0[maxn<<],sum1[maxn<<],lazy[maxn<<];
LL a[maxn],q1[maxn],q2[maxn];
int n,m,x;
void push_up(int rt){
sum0[rt]=sum0[rt<<]+sum0[rt<<|];
sum1[rt]=sum1[rt<<]+sum1[rt<<|];
return;
}
void push_down(int rt,int l,int r,int mid){
if(lazy[rt]==-) return;
lazy[rt<<]=lazy[rt];
lazy[rt<<|]=lazy[rt];
if(lazy[rt]==){
sum0[rt<<]=(mid-l+);
sum0[rt<<|]=r-mid;
sum1[rt<<]=;
sum1[rt<<|]=;
}else{
sum0[rt<<]=;
sum0[rt<<|]=;
sum1[rt<<]=mid-l+;
sum1[rt<<|]=r-mid;
}
lazy[rt]=-;
return;
}
void build(int l,int r,int rt){
lazy[rt]=-;
if(l==r){
//cout<<a[l]<<endl;
if(a[l]<=x){
sum0[rt]=;
sum1[rt]=;
}else{
sum1[rt]=;
sum0[rt]=;
}
return;
}
int mid=(l+r)>>;
build(lson);
build(rson);
push_up(rt);
} void update(int L,int R,int flag,int l,int r,int rt){
if(L>R) return;
if(L<=l&&r<=R){
if(flag==){
sum0[rt]=r-l+;
sum1[rt]=;
}else{
sum1[rt]=r-l+;
sum0[rt]=;
}
lazy[rt]=flag;
return;
}
int mid=(l+r)>>;
push_down(rt,l,r,mid);
if(L<=mid) update(L,R,flag,lson);
if(R>mid) update(L,R,flag,rson);
push_up(rt);
}
int query(int L,int R,int flag,int l,int r,int rt){
if(L>R) return ;
if(L<=l&&r<=R){
if(flag==){
// debug(l);debug(r);
// debug(rt);
// debug(sum0[rt]);
return sum0[rt];
}else{
return sum1[rt];
}
}
int mid=(l+r)>>;
push_down(rt,l,r,mid);
int ans=;
if(L<=mid) ans+=query(L,R,flag,lson);
if(R>mid) ans+=query(L,R,flag,rson);
return ans;
} int main() {
#ifndef ONLINE_JUDGE
FIN
#endif
scanf("%d%d%d",&n,&m,&x);
int tot1=,tot2=;
for(int i=;i<=n;i++){
scanf("%lld",&a[i]);
if(a[i]<=x){
tot1++;
q1[tot1]=q1[tot1-]+a[i];
}else{
tot2++;
q2[tot2]=q2[tot2-]+a[i];
}
}
build(,n,);
while(m--){
int op,l,r;
scanf("%d%d%d",&op,&l,&r);
if(op==){
LL ans=;
int cnt1=query(,l-,,,n,);
int cnt2=query(,r,,,n,);
// debug(cnt1);
// debug(cnt2);
ans+=q1[cnt2]-q1[cnt1];
int cnt3=query(,l-,,,n,);
int cnt4=query(,r,,,n,);
ans+=q2[cnt4]-q2[cnt3];
cout<<ans<<endl;
}else if(op==){
int cnt1=query(l,r,,,n,);
if(cnt1>)
update(l,l+cnt1-,,,n,);
update(l+cnt1,r,,,n,);
}else{
// debug(l);
// debug(r);
int cnt2=query(l,r,,,n,);
// debug(cnt2);
if(cnt2>)
update(l,l+cnt2-,,,n,);
update(l+cnt2,r,,,n,);
} }
return ;
}
J:
题解:
只是端点相交不算相交,其余都算,那么上板子搞就行(T字形也算)
#include<bits/stdc++.h>
using namespace std;
#define db double
const int maxn = 1e5 + ;
const double eps = 1e-;
inline sign(double a) {
return a < -eps ? - : a > eps;
}
inline int cmp(double a, double b) {
return sign(a - b);
}
struct P {
db x, y;
P() {};
P(db _x, db _y): x(_x), y(_y) {}
P operator+(P p) {
return {x + p.x, y + p.y};
}
P operator-(P p) {
return {x - p.x, y - p.y};
}
db dot(P p) {
return x * p.x + y * p.y;
}
db det(P p) {
return x * p.y - y * p.x;
}
};
#define cross(p1,p2,p3) ((p2.x-p1.x)*(p3.y-p1.y)-(p3.x-p1.x)*(p2.y-p1.y))
#define cross0p(p1,p2,p3) sign(cross(p1,p2,p3))
bool chkLL(P p1, P p2, P q1, P q2) { //直线平行
double a1 = cross(q1, q2, p1);
double a2 = -cross(q1, q2, p2);
return sign(a1 + a2) != ;
}
bool intersect(double l1, double r1, double l2, double r2) {
if(l1 > r1) swap(l1, r1);
if(l2 > r2) swap(l2, r2);
return !(cmp(r1, l2) == - || cmp(r2, l1) == -);
}
bool isSS(P p1, P p2, P q1, P q2) {
return intersect(p1.x, p2.x, q1.x, q2.x) && intersect(p1.y, p2.y, q1.y, q2.y) &&
cross0p(p1, p2, q1) * cross0p(p1, p2, q2) <= && cross0p(q1, q2, p1)
* cross0p(q1, q2, p2) <= ;
}
double rad(P p1, P p2) {
return atan2(p1.det(p2), p1.dot(p2));
}
bool xielv(P p1, P p2, P q1, P q2) {
P p = p2 - p1;
P q = q2 - q1;
if(q.det(p) == && cmp(rad(p, q), ) == ) return ;
return ;
}
struct node {
int u, v;
} edge[maxn];
int x[maxn];
int y[maxn];
int main() {
int n, m;
scanf("%d%d", &n, &m);
for(int i = ; i <= m; i++) {
scanf("%d%d", &edge[i].u, &edge[i].v);
}
for(int i = ; i <= n; i++) {
scanf("%d%d", &x[i], &y[i]);
}
int cnt = ;
for(int i = ; i <= m; i++) {
for(int j = i + ; j <= m; j++) {
P p1 = P{(double)x[edge[i].u], (double)y[edge[i].u]};
P p2 = P{(double)x[edge[i].v], (double)y[edge[i].v]};
P q1 = P{(double)x[edge[j].u], (double) y[edge[j].u]};
P q2 = P{(double)x[edge[j].v], (double)y[edge[j].v]};
if(isSS(p1, p2, q1, q2)) {
if(edge[i].u == edge[j].u || edge[i].u == edge[j].v || edge[i].v == edge[j].u || edge[i].v == edge[j].v) {
//printf("%lld %lld %lld %lld %lld %lld %lld %lld\n", p1.x,p1.y,p2.x,p2.y,q1.x,q1.y,q2.x,q2.y);
if(edge[i].u == edge[j].u && xielv(p1, p2, q1, q2)) cnt++;
if(edge[i].u == edge[j].v && xielv(p1, p2, q2, q1)) cnt++;
if(edge[i].v == edge[j].u && xielv(p2, p1, q1, q2)) cnt++;
if(edge[i].v == edge[j].v && xielv(p2, p1, q2, q1)) cnt++;
} else cnt++;
}
}
}
cout << cnt << endl;
}
CCPC-Winter Camp div2 day5的更多相关文章
- CCPC Wannafly Winter Camp Div2 部分题解
Day 1, Div 2, Prob. B - 吃豆豆 题目大意 wls有一个\(n\)行\(m\)列的棋盘,对于第\(i\)行第\(j\)列的格子,每过\(T[i][j]\)秒会在上面出现一个糖果, ...
- 2020 CCPC Wannafly Winter Camp Day1 C. 染色图
2020 CCPC Wannafly Winter Camp Day1 C. 染色图 定义一张无向图 G=⟨V,E⟩ 是 k 可染色的当且仅当存在函数 f:V↦{1,2,⋯,k} 满足对于 G 中的任 ...
- 2019 wannafly winter camp
2019 wannafly winter camp Name Rank Solved A B C D E F G H I J K day1 9 5/11 O O O O O day2 5 3/11 O ...
- 2019 wannafly winter camp day 3
2019 wannafly winter camp day 3 J 操作S等价于将S串取反,然后依次遍历取反后的串,每次加入新字符a,当前的串是T,那么这次操作之后的串就是TaT.这是第一次转化. 涉 ...
- 线段树优化建图(cf787d, 2019Wannafly Winter Camp Day7 Div1 E)
线段树优化建图,用于区间到区间建边时降低空间复杂度 建立两颗线段树,一颗in, 代表进入这个区间,一颗out,代表从这个区间出去 in树从父亲向儿子建边,代表宏观进入整个区间,不向下寻找 out树从儿 ...
- 2020 CCPC-Wannafly Winter Camp Day2
2020 CCPC-Wannafly Winter Camp Day2 A 托米的字符串 虽然每个子串出现的概率是相同的,但是同一长度的子串个数是不同的,所以要分别处理.计算出某一长度的情况下,元音字 ...
- CCPC-Wannafly Winter Camp Day5 (Div2, onsite) Sorting(线段树)
题目链接 题意 对序列进行三种操作: 1.区间求和. 2.将区间小于等于$x$的数不改变相对顺序的前提下放到$x$左边,用同样规则将比$x$大的放到右边. 3.将区间大于$x$的数不改变相对顺序的前提 ...
- CCPC-Wannafly Winter Camp Day5 (Div2, onsite)
Replay: Dup4: 时间复杂度算不对? 一点点思路不经过验证就激动的要死? 浪费自己一个小时还浪费别人一个小时? 对1e3不敏感? 1e3 * 1e3是多少? 模拟建边跑dp不写非要写个大模拟 ...
- 2019 CCPC-Wannafly Winter Camp Day5(Div2, onsite)
solve 5/11 补题:7/11 A Cactus Draw Code:zz Thinking :zz 题意:要在n*n的网格内画上一棵节点数为n树,使得没有边相交. 很好想的构造题,因为网格有n ...
随机推荐
- Struts2(九.初始化用户列表时显示用户照片数目)
1.userlist.jsp //显示每个用户照片的数目(遍历每个用户) $(".picture").each(function(i,e){ $.post("${page ...
- 【forEach控制器】-(针对,在不知道取到得参数有多少?但是要全部执行每一条的情况)
1.使用json提取器,提取全部参数 2.设置forEach控制器,他会自己把json提起器,取到得所有值,全部使用一次再停止. z
- 爬虫2.2-scrapy框架-文件写入
目录 scrapy框架-文件写入 1. lowb写法 2. 高端一点的写法 3. 优化版本 scrapy框架-文件写入 1. lowb写法 ~pipelines.py 前提回顾,spider.py中 ...
- PHP计算两个已知经纬度之间的距离
/** *求两个已知经纬度之间的距离,单位为千米 *@param lng1,lng2 经度 *@param lat1,lat2 纬度 *@return float 距离,单位千米 **/ privat ...
- adb 常用命令及操作
获取序列号: adb get-serialno 查看连接计算机的设备: adb devices 重启机器: adb reboot 重启到bootloader,即刷机模式: adb reboot boo ...
- 2018科大讯飞AI营销算法大赛全面来袭,等你来战!
AI技术已成为推动营销迭代的重要驱动力.AI营销高速发展的同时,积累了海量的广告数据和用户数据.如何有效应用这些数据,是大数据技术落地营销领域的关键,也是检测智能营销平台竞争力的标准. 讯飞AI营销云 ...
- 从hive导入到oracle(Hcatalog)
1.使用catalog的情况下: sqoop export --table tableName2 \ #oracle表 --connect jdbc:oracle:thin:@127.0.0.1:15 ...
- [leetcode-779-K-th Symbol in Grammar]
On the first row, we write a 0. Now in every subsequent row, we look at the previous row and replace ...
- mysql入门 — (2)
创建表 CREATE TABLE 表名称 [IF NOT EXISTS]( 字段名1 列类型[属性] [索引] 字段名2 列类型[属性] [索引] ... 字段名n 列类型[属性] [索引] )[表类 ...
- DNS域名解析协议
一. 根域 就是所谓的“.”,其实我们的网址www.baidu.com在配置当中应该是www.baidu.com.(最后有一点),一般我们在浏览器里输入时会省略后面的点,而这也已经成为了习惯. 根域服 ...