Preface
忙里偷闲补一下之前欠下的一些CF
这场前5个题都极其一眼,然而F瞪了好久愣是屁都不会
感觉现在水平有有点到瓶颈了,以前是Div2D写完卡现在是Div2E写完卡,但至少还是在进步的
A. Cover in Water
如果存在某个空地块的长度大于\(2\)则可以用两个块造出无限水,否则答案就是所有空位的个数
#include<cstdio>
#include<iostream>
#include<utility>
#include<vector>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<set>
#include<array>
#include<random>
#include<bitset>
#include<ctime>
#include<limits.h>
#include<assert.h>
#include<unordered_set>
#include<unordered_map>
#define RI register int
#define CI const int&
#define mp make_pair
#define fi first
#define se second
#define Tp template <typename T>
using namespace std;
typedef long long LL;
typedef long double LDB;
typedef unsigned long long u64;
typedef __int128 i128;
typedef pair <int,int> pi;
typedef vector <int> VI;
typedef array <int,3> tri;
const int N=105;
int t,n; char s[N];
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (scanf("%d",&t);t;--t)
{
RI i; int lst,sum=0,flag=0;
for (scanf("%d%s",&n,s+1),i=1;i<=n;++i)
{
if ((i==1||s[i-1]=='#')&&s[i]=='.') lst=i;
if (s[i]=='.'&&(i==n||s[i+1]=='#'))
{
int len=i-lst+1; if (len>2) flag=1; sum+=len;
}
}
printf("%d\n",flag?2:sum);
}
return 0;
}
B. Laura and Operations
能变成某一个数的充要条件是,另外两个数的奇偶性相同
构造一组解的话也很简单,首先把另外两个数中的一个用到\(0\),这样多余的那个个数一定是偶数
不妨设要变成\(1\),现在\(2\)还有偶数个,\(3\)已经用完了,我们重复若干次\((1,2)\to 3,(2,3)\to 1\)即可,每次操作可以消去\(2\)个\(2\)
#include<cstdio>
#include<iostream>
#include<utility>
#include<vector>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<set>
#include<array>
#include<random>
#include<bitset>
#include<ctime>
#include<limits.h>
#include<assert.h>
#include<unordered_set>
#include<unordered_map>
#define RI register int
#define CI const int&
#define mp make_pair
#define fi first
#define se second
#define Tp template <typename T>
using namespace std;
typedef long long LL;
typedef long double LDB;
typedef unsigned long long u64;
typedef __int128 i128;
typedef pair <int,int> pi;
typedef vector <int> VI;
typedef array <int,3> tri;
const int N=105;
int t,a[3];
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (scanf("%d",&t);t;--t)
{
RI i; for (i=0;i<3;++i) scanf("%d",&a[i]);
for (i=0;i<3;++i) putchar(a[(i+1)%3]%2==a[(i+2)%3]%2?'1':'0'),putchar(" \n"[i==2]);
}
return 0;
}
C. Anji's Binary Tree
直接在数上DP一下即可,设\(f_x\)表示走到\(x\)后要走到某个叶子节点最少所需修改次数
转移的话非常显然,注意当字符为L/R
时走对应一边时不需要额外的修改代价,否则要带上\(1\)的修改代价
#include<cstdio>
#include<iostream>
#include<utility>
#include<vector>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<set>
#include<array>
#include<random>
#include<bitset>
#include<ctime>
#include<limits.h>
#include<assert.h>
#include<unordered_set>
#include<unordered_map>
#define RI register int
#define CI const int&
#define mp make_pair
#define fi first
#define se second
#define Tp template <typename T>
using namespace std;
typedef long long LL;
typedef long double LDB;
typedef unsigned long long u64;
typedef __int128 i128;
typedef pair <int,int> pi;
typedef vector <int> VI;
typedef array <int,3> tri;
const int N=300005,INF=1e9;
int t,n,ls[N],rs[N],f[N]; char s[N];
inline void DFS(CI now=1)
{
if (ls[now]==0&&rs[now]==0) return (void)(f[now]=0); f[now]=INF;
if (ls[now]) DFS(ls[now]); if (rs[now]) DFS(rs[now]);
if (s[now]=='U') f[now]=min(f[now],min(f[ls[now]],f[rs[now]])+1);
if (s[now]=='L') f[now]=min(f[now],min(f[ls[now]],f[rs[now]]+1));
if (s[now]=='R') f[now]=min(f[now],min(f[ls[now]]+1,f[rs[now]]));
}
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (scanf("%d",&t);t;--t)
{
RI i; for (scanf("%d%s",&n,s+1),i=1;i<=n;++i) scanf("%d%d",&ls[i],&rs[i]);
f[0]=INF; DFS(); printf("%d\n",f[1]);
}
return 0;
}
D. Small GCD
很经典的约数容斥,看完题目就能想到
首先考虑将所有数从小到大排序,则此时相当于要计算:
\[\sum_{i=1}^n \sum_{j=i+1}^n \gcd(a_i,a_j)\times (n-j) \]乍一看不好计算,但有关\(\gcd\)的东西我们要么想到反演,要么就是约数容斥,这里显然是后者
我们枚举某个约数\(d\),将序列中满足\(d|a_i\)的位置\(i\)按顺序拿出来,此时整个式子中除了\(\gcd(a_i,a_j)\)外的贡献很容易统计
然后套约数容斥的板子,把每个数的真实贡献算清楚即可,具体实现看代码,复杂度\(O(n\sqrt a_i)\)
#include<cstdio>
#include<iostream>
#include<utility>
#include<vector>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<set>
#include<array>
#include<random>
#include<bitset>
#include<ctime>
#include<limits.h>
#include<assert.h>
#include<unordered_set>
#include<unordered_map>
#define int long long
#define RI register int
#define CI const int&
#define mp make_pair
#define fi first
#define se second
#define Tp template <typename T>
using namespace std;
typedef long long LL;
typedef long double LDB;
typedef unsigned long long u64;
typedef __int128 i128;
typedef pair <int,int> pi;
typedef vector <int> VI;
typedef array <int,3> tri;
const int N=100005;
int t,n,m,a[N],f[N]; vector <int> v[N];
signed main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (scanf("%lld",&t);t;--t)
{
RI i,j; for (m=0,scanf("%lld",&n),i=1;i<=n;++i)
scanf("%lld",&a[i]),m=max(m,a[i]);
for (i=1;i<=m;++i) f[i]=0,v[i].clear();
for (sort(a+1,a+n+1),i=1;i<=n;++i)
for (j=1;j*j<=a[i];++j) if (a[i]%j==0)
{
v[j].push_back(i);
if (j!=a[i]/j) v[a[i]/j].push_back(i);
}
int ans=0; for (i=m;i>=1;--i)
{
for (j=0;j<v[i].size();++j) f[i]+=j*(n-v[i][j]);
for (j=2*i;j<=m;j+=i) f[i]-=f[j]; ans+=f[i]*i;
}
printf("%lld\n",ans);
}
return 0;
}
E. Transitive Graph
这道更是傻逼题
有向图的传递闭包?那不就等价于跑个Tarjan缩点,在一个强连通分量里的所有点最后会变成一个团吗
然后又要求路径最长,那么显然一个强连通分量里的点最后都要选上
最后跑个拓扑排序,过程中维护下信息最优即可
#include<cstdio>
#include<iostream>
#include<utility>
#include<vector>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<set>
#include<array>
#include<random>
#include<bitset>
#include<ctime>
#include<limits.h>
#include<assert.h>
#include<unordered_set>
#include<unordered_map>
#define int long long
#define RI register int
#define CI const int&
#define mp make_pair
#define fi first
#define se second
#define Tp template <typename T>
using namespace std;
typedef long long LL;
typedef long double LDB;
typedef unsigned long long u64;
typedef __int128 i128;
typedef pair <int,int> pi;
typedef vector <int> VI;
typedef array <int,3> tri;
const int N=200005;
int t,n,m,a[N],x,y,dfn[N],low[N],stk[N],vis[N],col[N],tot,top,cnt,s[N],sz[N],deg[N];
pi f[N]; vector <int> v[N],nv[N];
inline void Tarjan(CI now)
{
dfn[now]=low[now]=++tot; stk[++top]=now; vis[now]=1;
for (int to:v[now]) if (!dfn[to]) Tarjan(to),low[now]=min(low[now],low[to]);
else if (vis[to]) low[now]=min(low[now],dfn[to]);
if (low[now]==dfn[now])
{
s[col[now]=++cnt]=-a[now]; sz[cnt]=1; vis[now]=0;
while (stk[top]!=now) s[col[stk[top]]=cnt]-=a[stk[top]],++sz[cnt],vis[stk[top--]]=0; --top;
}
}
signed main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (scanf("%lld",&t);t;--t)
{
RI i; for (scanf("%d%d",&n,&m),i=1;i<=n;++i) scanf("%d",&a[i]);
for (i=1;i<=m;++i) scanf("%d%d",&x,&y),v[x].push_back(y);
for (i=1;i<=n;++i) if (!dfn[i]) Tarjan(i);
for (i=1;i<=n;++i) for (auto j:v[i])
if (col[i]!=col[j]) nv[col[i]].push_back(col[j]),++deg[col[j]];
for (i=1;i<=cnt;++i) if (!deg[i]) f[i]=pi(sz[i],s[i]); else f[i]=pi(0,0);
queue <int> q; for (i=1;i<=cnt;++i) if (!deg[i]) q.push(i);
while (!q.empty())
{
int now=q.front(); q.pop();
for (auto to:nv[now])
{
f[to]=max(f[to],pi(f[now].fi+sz[to],f[now].se+s[to]));
if (!--deg[to]) q.push(to);
}
}
pi ans=pi(0,0); for (i=1;i<=cnt;++i) ans=max(ans,f[i]);
printf("%lld %lld\n",ans.fi,-ans.se);
for (i=1;i<=n;++i) v[i].clear(),dfn[i]=0;
for (i=1;i<=cnt;++i) nv[i].clear(),deg[i]=0; tot=cnt=0;
}
return 0;
}
Postscript
评价是题出的很好,希望下次我现场打的时候也能出这么合我胃口的DE,我可以展示1h切5题光速下班
标签:typedef,now,int,Codeforces,long,Div,include,911,define From: https://www.cnblogs.com/cjjsb/p/17873688.html