A.牛半仙的妹子数
Problem
Soluiton
- 思维 / 数学
首先观察到左边的数之和为 (a+b),令其为 (x),右边的数为 (c),令其为 (y)。并且左边加右边的和为定值 (a+b+c),令 (s=a+b+c)
有 (x+y = s)。
如果 (x>y),则 (x = x - y,y = 2y)。此时 (2y<s),所以 (2yequiv 2y pmod{s}) (1)(可能看起来有点别扭)
否则 (x le y),则 (x = 2x, y = y - x)。此时 (2y>s,y = y - x = y - s + y = 2y-s),所以 (2y equiv 2y-s pmod{s}) (2)。
又因为在 (1) 式中 (0 le 2y < s),在 (2) 式中 (0 le 2y-s < s),我们可以认为答案就是 (2^ky mod s)。
用快速幂,时间复杂度 (O(T log k))。
Code
Talk is cheap.Show me the code.
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read() {
int x = 0, f = 1; char ch = getchar();
while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); }
return x * f;
}
int a,b,c,k,mod;
int Pow(int x,int y) {
int res = 1, base = x;
while(y) {
if(y&1) res = res*base%mod; base = base*base%mod; y >>= 1;
}
return res;
}
void work() {
a = read(), b = read(), c = read(), k = read();
mod = a + b + c;
printf("%lld
",Pow(2,k)*c%mod);
}
signed main()
{
int T = read();
while(T--) work();
return 0;
}
B.牛半仙的妹子图
Problem
Solution
- SPFA
本题是稀疏图(ygt大佬说网格图是稀疏图可以卡掉SPFA),可以用 SPFA 处理从 s 到 i 的所有路径里面最大边最小是多少,记为 dismx[ i ]。然后按照题意模拟,统计一下答案,输出即可。时间复杂度 (O(km + q log 600))((O(km)) 是SPFA的复杂度,可以过)
Code
Talk is cheap.Show me the code.
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read() {
int x = 0, f = 1; char ch = getchar();
while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); }
return x * f;
}
const int N = 5e5+7, M = 607;
int n,m,q,s,mod,opt,cnt,tot,ntmp;
int c[N],head[N],dismx[N],ma[M],sum[M],cal[M],btmp[N];
bool flag[N];
struct Edge {
int next,to,w;
}edge[N<<1];
void add(int u,int v,int w) {
edge[++cnt] = (Edge)<%head[u],v,w%>;
head[u] = cnt;
}
void SPFA() {
bool vis[N];
queue<int> q;
memset(dismx, 0x3f, sizeof(dismx));
memset(vis, 0, sizeof(vis));
dismx[s] = 0; q.push(s); vis[s] = 1;
while(!q.empty()) {
int u = q.front(); vis[u] = 0; q.pop();
//if(u == n) printf("??? %d ???
",dismx[u]);
for(int i=head[u];i;i=edge[i].next) {
int v = edge[i].to, w = edge[i].w;
if(dismx[v] > max(dismx[u],w)) {
dismx[v] = max(dismx[u],w);
if(!vis[v]) {
q.push(v); vis[v] = 1;
}
}
}
}
}
int Get1(int x) {
int l = 1, r = ntmp, mid, ans = ntmp + 1;
while(l <= r) {
mid = (l + r) >> 1;
if(btmp[mid] >= x) {
ans = mid; r = mid - 1;
} else l = mid + 1;
}
return ans;
}
int Get2(int x) {
int l = 1, r = ntmp, mid, ans = 0;
while(l <= r) {
mid = (l + r) >> 1;
if(btmp[mid] <= x) {
ans = mid; l = mid + 1;
} else r = mid - 1;
}
return ans;
}
signed main()
{
//freopen("sample.in","r",stdin);
//freopen("x.txt","w",stdout);
n = read(), m = read(), q = read(), s = read(), opt = read();
if(opt == 1) mod = read();
for(int i=1;i<=n;++i) c[i] = read();
for(int i=1;i<=m;++i) {
int u = read(), v = read(), w = read();
add(u,v,w), add(v,u,w);
}
SPFA();
/*cout << "dismx" << endl;
for(int i=1;i<=n;++i) printf("%d ",dismx[i]);
cout << endl << endl;*/
memset(ma, 0x3f, sizeof(ma));
int INF = ma[0];
for(int i=1;i<=n;++i) {
ma[c[i]] = min(ma[c[i]], dismx[i]);
if(!flag[c[i]] && dismx[i]!=INF) {
++tot; flag[c[i]] = 1;
}
}
sort(ma+1, ma+1+600);
for(int i=1;i<=600;++i) btmp[i] = ma[i];
ntmp = unique(btmp+1, btmp+1+tot) - btmp - 1;
for(int i=1;i<=tot;++i) {
int x = lower_bound(btmp+1, btmp+1+ntmp, ma[i]) - btmp;
//printf("%d ",x);
++cal[x];
}
/*printf("btmp-ma:
");
for(int i=1;i<=ntmp;++i) printf("%d ",btmp[i]);
cout << endl;
printf("cal:
");
for(int i=1;i<=ntmp;++i) printf("%d ",cal[i]);
cout << endl;*/
for(int i=1;i<=ntmp;++i) cal[i] += cal[i-1];
for(int i=1;i<ntmp;++i) sum[i] = sum[i-1] + cal[i]*(btmp[i+1]-btmp[i]);
/*printf("sum:
");
for(int i=1;i<ntmp;++i) printf("%d ",sum[i]);
cout << endl << endl;*/
int ans = 0;
while(q--) {
int l = read(), r = read();
if(opt == 1) {
l = (l xor ans) % mod + 1;
r = (r xor ans) % mod + 1;
if(l > r) swap(l, r);
}
ans = 0;
int ml = Get1(l), mr = Get2(r);
//printf(" %d %d
",ml,mr);
if(mr == 0) ans = 0;
else if(ml == ntmp+1) ans = (r - l + 1) * tot;
else {
//printf(" %d %d
",ml,mr);
ans += (btmp[ml] - l) * (cal[ml-1]);
ans += (sum[mr-1] - sum[ml-1]);
ans += (r - btmp[mr]+1) * cal[mr];
}
printf("%lld
",ans);
}
return 0;
}
/*
8 15 1 1 0
4 3 4 2 3 1 2 1
1 2 7
1 3 6
1 4 6
3 5 13
1 6 13
5 7 8
4 8 15
4 3 15
7 3 9
2 4 13
6 7 7
8 1 5
5 8 14
6 8 3
6 5 5
0 27
96
*/
C.牛半仙的妹子Tree
Problem
Solution
-
ST表求LCA((O(n log n)) 预处理,(O(1)) 查询,常数较大)
-
操作分块思想
以清空操作为分界点,把操作序列分成 (k) 块。
-
对于一个大小为 s 的块,且用 lca法 判断查询操作:最劣的情况下有 (frac{s}{2}) 个加入操作,(frac{s}{2}) 个查询操作,lca法 判断一个点的复杂度是 (O(1)),故判断 (frac{s}{2}) 个点的复杂度是 (O(frac{s}{2})),该块的所有操作复杂度 (O(frac{s^2}{4})),由于 lca法 的常数较大,可以把复杂度近似为 (O(s^2))
-
对于一个大小为 s 的块,且用 bfs法 判断查询操作:复杂度 (O(n))
对于以上两种方法的分析,于是我们可以:
对于一个大小大于 (sqrt{m}) 的块,用 bfs法 判断查询操作,块内总复杂度 (O(n)),均摊到每个查询操作上 (O(sqrt{n}))。
对于一个大小小于 (sqrt{m}) 的块,有 lca法 判断查询操作,每个查询操作复杂度 (O(sqrt{m}))。
对于所有查询操作,总时间复杂度 (O(nsqrt{n})) 级别。(n le 10^5),可以通过。
Code
Talk is cheap.Show me the code.
#include<bits/stdc++.h>
#define mp make_pair
#define fi first
#define se second
#define pb push_back
using namespace std;
inline int read() {
int x = 0, f = 1; char ch = getchar();
while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); }
return x * f;
}
typedef pair<int,int> PII;
const int N = 1e5+7;
int n,m,cnt,dcnt,qcnt;
int head[N],dep[N],dfn[N<<1],pos[N],ST[N<<1][20],lg[N<<1],opt[N],X[N],qs[N],qt[N],id[N<<1];
vector<int> ans;
struct Edge {
int next,to;
}edge[N<<1];
inline void add(int u,int v) {
edge[++cnt] = (Edge)<%head[u],v%>;
head[u] = cnt;
}
void Dfs(int u,int fa) {
dep[u] = dep[fa] + 1;
++dcnt; dfn[dcnt] = dcnt; pos[u] = dcnt; id[dcnt] = u;
for(int i=head[u];i;i=edge[i].next) {
int v = edge[i].to;
if(v != fa) {
dfn[++dcnt] = pos[u]; Dfs(v,u);
}
}
}
void Init() {
for(int i=2;i<=dcnt;++i) lg[i] = lg[i>>1] + 1;
for(int i=1;i<=dcnt;++i) ST[i][0] = dfn[i];
for(int j=1;j<20;++j) {
for(int i=1;i+(1<<j)-1<=dcnt;++i) {
ST[i][j] = min(ST[i][j-1], ST[i+(1<<(j-1))-1][j-1]);
}
}
}
int dist(int x,int y) {
int px = pos[x], py = pos[y];
if(px > py) swap(px,py);
int L = py - px + 1;
int lca = id[min(ST[px][lg[L]], ST[py-(1<<lg[L])+1][lg[L]])];
return dep[x] + dep[y] - 2*dep[lca];
}
void Calc1(int s,int t) {
vector<PII> ma;
for(int i=s;i<t;++i) {
if(opt[i] == 1) {
ma.pb(mp(X[i],i));
} else {
bool flag = 0;
for(int k=0;k<ma.size();++k) {
if(dist(ma[k].fi, X[i]) <= i-ma[k].se) {
flag = 1; break;
}
}
ans.pb(flag);
}
}
}
void Calc2(int s,int t) {
bool vis[N]; queue<int> q;
memset(vis, 0, sizeof(vis));
for(int i=s;i<t;++i) {
int step = q.size();
while(step--) {
int u = q.front(); q.pop();
for(int i=head[u];i;i=edge[i].next) {
int v = edge[i].to;
if(!vis[v]) {
vis[v] = 1; q.push(v);
}
}
}
if(opt[i] == 1) vis[X[i]] = 1, q.push(X[i]);
else ans.pb(vis[X[i]]);
}
}
int main()
{
n = read(), m = read();
for(int i=1;i<n;++i) {
int u = read(), v = read();
add(u,v), add(v,u);
}
//cout << endl;
Dfs(1,0); Init();
qs[++qcnt] = 1;
for(int i=1;i<=m;++i) {
opt[i] = read(), X[i] = read();
if(opt[i] == 2) {
qt[qcnt] = i; qs[++qcnt] = i + 1;
}
}
qt[qcnt] = m + 1;
//cout << endl;
//for(int i=1;i<=qcnt;++i) printf("%d %d
",qs[i],qt[i]);
for(int i=1;i<=qcnt;++i) {
int qn = qt[i] - qs[i];
if(qn <= sqrt(m)) {
//puts("test");
Calc1(qs[i], qt[i]);
} else {
Calc2(qs[i], qt[i]);
}
}
for(int i=0;i<ans.size();++i) {
if(ans[i] == 1) puts("wrxcsd");
else puts("orzFsYo");
}
return 0;
}
/*
5 4
1 2
1 3
2 4
2 5
1 2
3 2
2 4
3 4
wrxcsd
orzFsYo
*/