CSP-S加赛0909
下发文件
A. 元素周期表
内存限制:128 MiB
时间限制:1000 ms
标准输入输出
题目类型:传统
评测方式:文本比较
题目描述
输入格式
输出格式
样例
数据范围与提示
脑子不够,图论来凑
发现有了(x1,y1)、(x1,y2)、(x2,y1)就可以获得(x2,y2),可以愉快地想到图论. 就是把x2和y1连边、把x1和y2连边,这样可以获得一个叉形图. 然后把x1与y1连边,你发现了什么?

没错!就是强连通分量!
这样题目就转化为了求最少加几条边使得整个图强连通.
那就非常简单了.
点击查看代码
#include<bits/stdc++.h>
#define ll int
#define rg register
#define rll rg ll
#define maxn 400001
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
static inline ll read()
{
rll f=0,x=0;rg char ch=getchar();
while(ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar();
return f?-x:x;
}
static inline void write(rll x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);putchar(x%10|'0');
}
ll n,m,q;
vector<ll> g[maxn];
ll dfn[maxn],low[maxn],cnt,tot;
bool fl[maxn];
stack<ll> st;
inline void tarjan(ll x)
{
dfn[x]=low[x]=++cnt;st.push(x);fl[x]=1;
for(rll i=0;i<g[x].size();i++)
{
rll to=g[x][i];
if(!dfn[to]) tarjan(to),low[x]=min(low[x],low[to]);
else if(fl[to]) low[x]=min(low[x],dfn[to]);
}
if(dfn[x]==low[x])
{
rll t;tot++;
do { t=st.top();st.pop(); } while(t!=x);
}
}
int main()
{
n=read();m=read();q=read();
for(rll i=1,r,c;i<=q;i++) r=read(),c=read(),g[r].push_back(n+c),g[n+c].push_back(r);
for(rll i=1;i<=n+m;i++) if(!dfn[i]) tarjan(i);
write(tot-1);
return 0;
}
B. gcd
内存限制:256 MiB
时间限制:1000 ms
标准输入输出
题目类型:传统
评测方式:文本比较
题目描述
输入格式
输出格式
样例
数据范围与提示
题目的大意即是给定n个数,求出这n个数中互质的无序数对的个数,且要支持修改.
对于这种个数的问题,自然会想到类似dp的做法. 那么可以尝试:
设f[i]为最大公约数为i的数对个数,
g[i]为最大公约数为i的倍数的数对个数,
s[i]为i的倍数的数字的个数.
对于s[i]可以非常轻易地求出,每次枚举的时候暴力加就行了,即枚举每一个数的约数,把这个约数的s值加1.
如何将s[i]与g[i]产生联系呢?
手模一下不难发现有以下结论:
.
有了g[i],且显然已知f[i]与g[i]的关系为:
.
这是什么?
莫比乌斯反演!
(如果不知道莫反是什么的话还请移步先学习它,因为它在数论题解题方面非常重要,所以还是有必要一学的.)
根据莫反的性质,可以得到如下式子:
.
最后把1到n的f值加起来,即为答案. 发现f值其实并没有其他用处,因此可以直接计算,累加答案.
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define maxn 1000001
#define pll pair<ll,ll>
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
static inline ll read()
{
rll f=0,x=0;rg char ch=getchar();
while(ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar();
return f?-x:x;
}
static inline void write(rll x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);putchar(x%10|'0');
}
ll n,m,k,op,ans;
ll a[maxn];
ll g[maxn],s[maxn];
ll prime[maxn],miu[maxn],cnt;
bool fl[maxn],sel[maxn];
static inline void xxs()
{
miu[1]=1;
for(rll i=2;i<maxn;i++)
{
if(!fl[i]) prime[++cnt]=i,miu[i]=-1;
for(rll j=1;j<=cnt&&i*prime[j]<maxn;j++)
{
fl[i*prime[j]]=1;
if(!(i%prime[j])) break;
miu[i*prime[j]]=-miu[i];
}
}
}
int main()
{
xxs();n=read();m=read();
for(rll i=1;i<=n;i++) a[i]=read();
while(m--)
{
k=read();sel[k]^=1;op=sel[k]?1:-1;
for(rll i=1;i<=sqrt(a[k]);i++)
if(!(a[k]%i))
{
s[i]+=op;if(i!=a[k]/i) s[a[k]/i]+=op;
ans-=miu[i]*g[i];if(i!=a[k]/i) ans-=miu[a[k]/i]*g[a[k]/i];
g[i]=s[i]*(s[i]-1)>>1;if(i!=a[k]/i) g[a[k]/i]=s[a[k]/i]*(s[a[k]/i]-1)>>1;
ans+=miu[i]*g[i];if(i!=a[k]/i) ans+=miu[a[k]/i]*g[a[k]/i];
}
write(ans);putn;
}
return 0;
}
--END--





浙公网安备 33010602011771号
我的博客: 𝟷𝙻𝚒𝚞
本文链接: https://www.cnblogs.com/1Liu/p/16623891.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!