A

矩阵树定理可以用于最小生成树计数,最直观的做法就是求个mst,再用矩阵树定理求最小生成树个数,但是n<=1e5,显然不是o(n^3)可以做出来的。

考虑随机数据生成器,固定1e5的边,但是边权在unsigned long long的范围内随机指定,由样例看出,即使是点数很少的情况下,最多也只有一个生成树

于是,我们猜测,只需要做一遍最小生成树,并假定不会有更多的生成树就可以了。

#include<bits/stdc++.h>
#define ull unsigned long long
using namespace std;
const int maxn = ;
const ull mod = ;
int f[maxn];
int findf(int x){
return f[x] == x ? x : f[x] = findf(f[x]);
}
int n,m;
ull k1,k2;
struct edge{
int u;
int v;
ull w;
friend bool operator < (edge a,edge b){
return a.w < b.w;
}
}e[maxn];
ull xorS(){
ull k3 = k1,k4 = k2;
k1 = k4;
k3 ^= k3 << ;
k2 = k3 ^ k4 ^ (k3 >> ) ^ (k4 >> );
return k2 + k4;
}
int main(){
int T;
cin>>T;
while(T--){
cin>>n>>m>>k1>>k2;
for(int i = ;i <= m;i++){
e[i].u = xorS() % n + ;
e[i].v = xorS() % n + ;
e[i].w = xorS();
}
sort(e+,e++m);
for(int i = ;i <= n;i++){
f[i] = i;
}
ull tot = ;
int uu,vv,cnt = ;
for(int i = ;i <= m;i++){
uu = e[i].u;
vv = e[i].v;
uu = findf(uu);
vv = findf(vv);
if(uu == vv) continue;
else{
cnt++;
e[i].w %= mod;
tot = (tot + e[i].w) % mod;
f[uu] = vv;
}
}
if(cnt != n-) tot = ;
cout<<tot<<endl;
}
return ;
}

G

选择k个路径,它们至少有一个交点,首先先把路径经过的点标记一下,对于一个点,它被选中,至少要有k个路径经过它。

这样就有一个需要考虑的地方,如果这k个路径有不止一个交点,就会被重复统计,如何去重?

两条路径的交点,只可能是树上连续的一段,所以多条路径的交点,也只能是树上的一段,对于一个方案,可以只在深度最小的那个点统计一次,而这个点,肯定是某个路径深度最小的点。

遍历每个点,新加进去以这个点为lca的路径,和经过这个点的其他路径联合起来算对方案的贡献。

如何快速计算一个点经过多少路径?可以让深度最深的点+1,走出这条路径或者达到交点(lca)时-1,也就是树上差分。

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <vector>
#define fo(i, l, r) for (long long i = l; i <= r; i++)
#define fd(i, l, r) for (long long i = r; i >= l; i--)
#define mem(x) memset(x, 0, sizeof(x))
#define ll long long
#define ld double
using namespace std;
const int maxn = ;
const ll mod = 1e9 + ;
ll read()
{
ll x = , f = ;
char ch = getchar();
while (!(ch >= '' && ch <= ''))
{
if (ch == '-')
f = -;
ch = getchar();
};
while (ch >= '' && ch <= '')
{
x = x * + (ch - '');
ch = getchar();
};
return x * f;
}
int n, m, k;
vector<int> g[maxn];
int d[maxn];
int fa[maxn][];
void dfs(int u, int f, int deep)
{
d[u] = deep;
fa[u][] = f;
int t = ;
while (fa[u][t] && fa[fa[u][t]][t])
{
fa[u][t + ] = fa[fa[u][t]][t];
t++;
}
int sz = (int)g[u].size() - , v;
fo(i, , sz)
{
v = g[u][i];
if (v == f)
continue;
dfs(v, u, deep + );
}
}
int lca(int u, int v)
{
if (d[u] < d[v])
swap(u, v);
int delta = d[u] - d[v];
int t = ;
while (delta)
{
if (delta & )
u = fa[u][t];
t++;
delta >>= ;
}
if (u == v)
return u;
t = ;
while (t >= )
{
if (fa[u][t] != fa[v][t])
{
u = fa[u][t];
v = fa[v][t];
t++;
}
else
{
t--;
}
}
return fa[u][];
}
int addamt[maxn], cf[maxn], uu[maxn], vv[maxn]; ll fac[maxn], inv[maxn];
ll ans;
ll C(ll n, ll m)
{
return fac[n] * inv[m] % mod * inv[n - m] % mod;
}
void dfs2(int u)
{
int v, sz = (int)g[u].size() - ;
fo(i, , sz)
{
v = g[u][i];
if (v == fa[u][])
continue;
dfs2(v);
cf[u] += cf[v];
}
}
int main()
{
//freopen("data.in","r",stdin);
fac[] = fac[] = ;
fo(i, , maxn - )
{
fac[i] = (fac[i - ] * i) % mod;
}
inv[] = inv[] = ;
fo(i, , maxn - )
{
inv[i] = (mod - (mod / i)) * inv[mod % i] % mod;
}
fo(i, , maxn - )
{
inv[i] = (inv[i] * inv[i - ]) % mod;
}
int T = read();
while (T--)
{
memset(fa, , sizeof(fa));
memset(d, , sizeof(d));
ans = ;
n = read();
m = read();
k = read();
fo(i, , n) g[i].clear();
int u, v;
fo(i, , n - )
{
u = read();
v = read();
g[u].push_back(v);
g[v].push_back(u);
}
fo(i, , m)
{
uu[i] = read();
vv[i] = read();
}
dfs(, , );
fo(i, , n) cf[i] = addamt[i] = ;
int zz, cd;
fo(i, , m)
{
zz = lca(uu[i], vv[i]);
addamt[zz]++;
cf[uu[i]]++;
cf[vv[i]]++;
cf[zz]--;
cf[fa[zz][]]--;
}
dfs2();
fo(i, , n)
{
cf[i] -= addamt[i];
fo(j, , addamt[i])
{ if (j > k)
break;
if (cf[i] >= k - j){
ans = (ans + C(cf[i], k - j) * C(addamt[i], j) % mod) % mod;
}
}
}
printf("%lld\n", ans);
}
return ;
}

H

如果区间的数量不大于颜色数,那么每个区间染上不同的颜色就可以了。

如果有断层,尽量染上缺少的颜色,如果区间比较多,如何确保染到一个最优的颜色?

某些颜色在大于某个位置就没有了,如果染上那个最早失效的颜色,就可能会使答案增大。

对于每个颜色,维护一个它消失的位置,每次取出那个消失位置最靠前的染色。

这个题spj有毛病,行尾有空格算你wa,是真的无语。

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <vector>
#define fo(i, l, r) for (long long i = l; i <= r; i++)
#define fd(i, l, r) for (long long i = r; i >= l; i--)
#define mem(x) memset(x, 0, sizeof(x))
#define ll long long
#define ld double
using namespace std;
const int maxn = ;
const ll mod = 1e9 + ;
ll read()
{
ll x = , f = ;
char ch = getchar();
while (!(ch >= '' && ch <= ''))
{
if (ch == '-')
f = -;
ch = getchar();
};
while (ch >= '' && ch <= '')
{
x = x * + (ch - '');
ch = getchar();
};
return x * f;
}
struct dat{
int p;
ll v;
friend bool operator < (dat a,dat b){
return a.v > b.v;
}
}now,nxt,col;
priority_queue<dat> q,ys;
ll n,k,ans[maxn],op[maxn],ed[maxn],cnt[maxn];
ll tot;
int main()
{
int T=read();
while(T--){
tot=;
while(!q.empty())q.pop();
while(!ys.empty())ys.pop();
n=read();k=read();
if(k>n)k=n;
fo(i,,n)ans[i]=;
fo(i,,k)cnt[i]=;
int nowp=,nowk=;
fo(i,,n){
now.p=i;
now.v=read();
q.push(now);
op[i] = now.v;
now.v=read();
q.push(now);
ed[i] = now.v;
}
fo(i,,k){
now.p=i;
now.v=-;
ys.push(now);
}
while(!q.empty()){
now=q.top();
q.pop();
if(ans[now.p]){
cnt[ans[now.p]]--;
if(cnt[ans[now.p]]==) nowk--;
}else{
col=ys.top();
ys.pop();
ans[now.p] = col.p;
cnt[col.p]++;
if(cnt[col.p]==) nowk++;
col.v = max(col.v,(ll)ed[now.p]);
ys.push(col);
}
nowp = now.v;
if(!q.empty()){
nxt=q.top();
if(nxt.v == now.v) continue;
else{
if(nowk >= k) tot += nxt.v - now.v;
}
}
}
printf("%lld\n",tot);
printf("%lld",ans[]);
fo(i,,n) printf(" %lld",ans[i]);
putchar('\n');
}
return ;
}

M

首先预处理每个灯照亮的边,它是一段连续的区间。

能不能照亮某个边,需要 点与边的两个端点的连线不经过凸包内部,可以利用叉积快速判断,逆时针方向下只要点在边的右边就可以。

处理之后,要做一个线段覆盖,由于是环,需要做n次

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <set>
#include <cmath>
#include <queue>
#include <map>
#include <ctime>
#define ll long long
#define ld double
#define lson rt << 1, l, m
#define pi acos(-1)
#define rson rt << 1 | 1, m + 1, r
#define fo(i, l, r) for (int i = l; i <= r; i++)
#define fd(i, l, r) for (int i = r; i >= l; i--)
#define mem(x) memset(x, 0, sizeof(x))
#define eps 1e-11
using namespace std;
const ll maxn = ;
const ll mod = ;
ll read()
{
ll x = , f = ;
char ch = getchar();
while (!(ch >= '' && ch <= ''))
{
if (ch == '-')
f = -;
ch = getchar();
};
while (ch >= '' && ch <= '')
{
x = x * + (ch - '');
ch = getchar();
};
return x * f;
}
int sgn(double x)
{
if (fabs(x) < eps)
return ;
if (x < )
return -;
else
return ;
}
struct Point
{
double x, y;
Point() {}
Point(double _x, double _y)
{
x = _x;
y = _y;
}
double operator^(const Point &b) const
{
return x * b.y - y * b.x;
}
double operator*(const Point &b) const
{
return x * b.x + y * b.y;
}
Point operator-(const Point &b) const
{
return Point(x - b.x, y - b.y);
}
} pts[maxn],bulb[maxn];
struct Line
{
Point s, e;
Line() {}
Line(Point _s, Point _e)
{
s = _s;
e = _e;
}
int linecrossseg(Line v)
{
int d1 = sgn((e - s) ^ (v.s - s));
int d2 = sgn((e - s) ^ (v.e - s));
if ((d1 ^ d2) == -)
return ;
return (d1 == || d2 == );
}
int relation(Point p)
{
int c = sgn((p - s) ^ (e - s));
if (c < )
return ;
else if (c > )
return ;
else
return ;
}
bool parallel(Line v)
{
return sgn((e - s) ^ (v.e - v.s)) == ;
}
int linecrossline(Line v)
{
if (this->parallel(v))
return v.relation(s) == ;
return ;
}
Point crosspoint(Line v)
{
double a1 = (v.e-v.s) ^ (s-v.s);
double a2 = (v.e-v.s) ^ (e-v.s);
return Point((s.x * a2-e.x * a1) / (a2-a1), (s.y * a2-e.y * a1) / (a2-a1));
}
}A,B;
int n,m;
int lp[maxn],rp[maxn];
int rec[maxn],tmp[maxn];
int ans,tot;
struct dat{
int p,l,r;
friend bool operator < (dat a,dat b){
if(a.l != b.l) return a.l < b.l;
else return a.r > b.r;
}
}dats[maxn];
int main()
{
int T=read();
while(T--){
n=read();m=read();
fo(i,,m) lp[i]=rp[i]=;
fo(i,,n){
pts[i].x=read();
pts[i].y=read();
pts[n+i] = pts[i];
}
fo(i,,m){
bulb[i].x=read();
bulb[i].y=read();
bool lst=false,cur=false;
rp[i]=n;
fo(j,,n){
A = Line(pts[j],pts[j+]);
if(A.relation(bulb[i])!=)cur=false;
else cur=true;
if(!lst&&cur) lp[i]=j;
if(lst&&!cur){
rp[i]=j-;
}
lst = cur;
}
if(rp[i]<lp[i])rp[i]+=n;
dats[i].l=lp[i];dats[i].r=rp[i];dats[i].p=i;
}
sort(dats+,dats++m);
ans = m + ;
fo(t,,n){
tot = ;
int pt = t,pp,vv=-;
fo(i,,m){
tmp[i]=false;
}
fo(i,,m){
if(pt >= t+n)break;
if(dats[i].l > pt){
pt = vv + ;
tot++;
tmp[pp]=true;
}
if(dats[i].l<=pt&&dats[i].r>=pt){
if(vv<dats[i].r){
pp=dats[i].p;
vv=dats[i].r;
}
}
}
if(pt<t+n && vv>=t+n-){
pt = vv+;
tot++;
tmp[pp]=true;
}
if(pt>=t+n&&ans>tot){
ans=tot;
fo(i,,m) rec[i]=tmp[i];
}
}
if(ans==m+){
printf("-1\n");
continue;
}
printf("%d\n",ans);
bool fst=true;
fo(i,,m){
if(rec[i]){
if(fst) fst=false;
else putchar(' ');
printf("%d",i);
}
}
putchar('\n');
}
return ;
}

I

要构造一个最长上升子序列长度至少为n-1的序列,可以让一个数移动到另一个数后边,这样就有o(n^2)个

每个序列,经过排序之后,若符合条件,那么一定在这些目标序列之内。

可以倒着枚举哪些排序器起到了作用。

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <vector>
#define fo(i, l, r) for (long long i = l; i <= r; i++)
#define fd(i, l, r) for (long long i = r; i >= l; i--)
#define mem(x) memset(x, 0, sizeof(x))
#define ll long long
#define ld double
using namespace std;
const int maxn = ;
const ll mod = 1e9 + ;
ll read()
{
ll x = , f = ;
char ch = getchar();
while (!(ch >= '' && ch <= ''))
{
if (ch == '-')
f = -;
ch = getchar();
};
while (ch >= '' && ch <= '')
{
x = x * + (ch - '');
ch = getchar();
};
return x * f;
}
struct dat{
int v[];
}now,nxt,dats[maxn];
int n,m,cnt;
int a[],b[];
ll q,ans;
void dfs(int u,int d){
if(d > m){
ans++;
return;
}
int aa=a[m-d+],bb=b[m-d+];
if(dats[u].v[aa] > dats[u].v[bb]) return;
dfs(u,d+);
swap(dats[u].v[aa],dats[u].v[bb]);
dfs(u,d+);
swap(dats[u].v[aa],dats[u].v[bb]);
}
int main()
{
int T=read();
while(T--){
n=read();
m=read();
q=read();
cnt=ans=;
fo(i,,m){
a[i]=read();
b[i]=read();
}
fo(i,,n){
dats[].v[i]=i;
}
fo(i,,n){
fo(j,,n){
now = dats[];
if(i==j||i==j+||i==j-)continue;
if(j<i){
int tmp = i;
fd(k,j+,i-){
swap(now.v[k],now.v[k+]);
}
now.v[j+]=tmp;
}else{
int tmp = i;
fo(k,i+,j){
swap(now.v[k],now.v[k-]);
}
now.v[j]=tmp;
}
cnt++;
dats[cnt]=now;
}
}
cnt++;
dats[cnt] = dats[];
fo(i,,cnt){
dfs(i,);
}
ans %= mod;
printf("%lld\n",ans);
}
return ;
}

2018 icpc 徐州的更多相关文章

  1. 2018 ICPC 徐州网络赛

    2018 ICPC 徐州网络赛 A. Hard to prepare 题目描述:\(n\)个数围成一个环,每个数是\(0\)~\(2^k-1\),相邻两个数的同或值不为零,问方案数. solution ...

  2. 2018 icpc 徐州网络赛 F Features Track

    这个题,我也没想过我这样直接就过了 #include<bits/stdc++.h> using namespace std; ; typedef pair<int,int> p ...

  3. 2018 icpc 徐州现场赛G-树上差分+组合数学-大佬的代码

    现场赛大佬打印的代码,观摩了一哈. 写了注释,贴一下,好好学习.%%%PKU 代码: //树上差分(LCA) #include<bits/stdc++.h> #define For(i,x ...

  4. 2018 ICPC 徐州邀请赛 总结

    Day 0 上午在高铁里面,很困但是睡不着…… 中午到矿大报道. 食堂饭菜不错,有西瓜,就是有点辣. 下午热身赛,D题队友想了个假算法……GG. 评测机摸底考试正常进行. 热身赛之后精疲力尽,赶到宾馆 ...

  5. 2018 ICPC 徐州网络预赛 Features Track (STL map pair)

    [传送门]https://nanti.jisuanke.com/t/31458 [题目大意]有N个帧,每帧有K个动作特征,每个特征用一个向量表示(x,y).两个特征相同当且仅当他们在不同的帧中出现且向 ...

  6. 2018 ICPC 沈阳网络赛

    2018 ICPC 沈阳网络赛 Call of Accepted 题目描述:求一个算式的最大值与最小值. solution 按普通算式计算方法做,只不过要同时记住最大值和最小值而已. Convex H ...

  7. 2018 ICPC Asia Singapore Regional A. Largest Triangle (计算几何)

    题目链接:Kattis - largesttriangle Description Given \(N\) points on a \(2\)-dimensional space, determine ...

  8. 2018 ICPC Pacific Northwest Regional Contest I-Inversions 题解

    题目链接: 2018 ICPC Pacific Northwest Regional Contest - I-Inversions 题意 给出一个长度为\(n\)的序列,其中的数字介于0-k之间,为0 ...

  9. 【2018 ICPC亚洲区域赛徐州站 A】Rikka with Minimum Spanning Trees(求最小生成树个数与总权值的乘积)

    Hello everyone! I am your old friend Rikka. Welcome to Xuzhou. This is the first problem, which is a ...

随机推荐

  1. 【Java】 Java反射机制总结

    一.什么是反射 在运行状态中,对于任意一个类,都能够获取到这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性(包括私有的方法和属性),这种动态获取的信息以及动态调用对象的方法的 ...

  2. 012-zabbix主动模式

    6.1 主动模式 zabbix agent检测分为主动(agent active)和被动(agent)两种形式,主动与被动的说法均是相对于agent来讨论的.简单说明一下主动与被动的区别如下: 主动: ...

  3. flex布局总结回顾

    1.背景 传统css盒式模型,依赖 display属性 + position属性 + float属性实现页面的布局,而随着互联网的迅猛发展,带动了无数的互联网创业者和互联网产品,因而样式布局的美化成为 ...

  4. exe远程注入线程xp

    进程删除不了 某目录下txt ini config 无法修改

  5. Sublime Text2 常用快捷键总结

    Ctrl+Tab 当前窗口中的标签页切换 Ctrl+Shift+D 复制光标所在整行,插入在该行之前 Ctrl+Shift+K 删除整行 Ctrl+Shift+/ 注释已选择内容 Ctrl+Shift ...

  6. npm 发布 vue 组件

    创建 vue 组件 1.创建vue项目,为了简洁方便,推荐使用webpack-simple构建一个项目 vue init webpack-simple your-project 2.在 src 目录下 ...

  7. 七、设备驱动中的阻塞与非阻塞 IO(二)

    7.2 轮询 7.2.1 介绍 在用户程序中的 select() 和 poll() 函数最终会使设备驱动中的 poll() 函数被执行. 设备驱动程序中的轮询函数原型: /** 用于询问设备是否可以非 ...

  8. 【HDU4034】Graph

    题目大意:给定一个图的最短路,求原图中至少存在多少条边. 题解:利用 Floyd 的性质,枚举边 d[i][j],若存在一个不是两端点的点,使得 d[i][j]=d[i][k]+d[k][j] 成立, ...

  9. ESP8266-Station模式--我想连上谁

    Station模式又叫做站点工作模式,类似于无线终端 处于Station模式下的ESP8266,可以连接到AP.通过Station(简称为“STA”)模式,ESP8266作为客户端连接到路由的wifi ...

  10. 浅谈Mybatis通用Mapper使用方法_java - JAVA

    文章来源:嗨学网 敏而好学论坛www.piaodoo.com 欢迎大家相互学习 对单表进行增删改查是项目中不可避免的需求,Mybatis的通用Mapper插件使这些操作变得简单 添加maven依赖 在 ...