赞
踩
A.手玩题:
可以通过最后一个样例,如果是长度为3的连续O,直接在两边放就行,然后一直用中间的水填到其他地方
- #include<bits/stdc++.h>
- using namespace std;
- const int N = 3e5+10,mod= 998244353;
- #define int long long
- int n,m,k;
-
- void solve()
- {
- cin>>n;
- string s;
- cin>>s;
- s="?"+s;
- int res=0;
- int now=0;
- s+="#";
- for(int i=1;i<=n+1;i++){
- if(s[i]=='#')
- {
- if(now>=3){
- cout<<2<<"\n";
- return ;
- }
- res+=min(2ll,now);
- now=0;
- }
- else now++;
- }
- cout<<res<<"\n";
- }
-
- signed main()
- {
- cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
- int t=1;
- cin>>t;
- while(t--) solve();
- }

B:
直接每个数字都去判定能不能成为最后一个
假设都变成 a
然后目标变成 让 b c的数量相同
假设只操作b c,那么他们的差都减一,差奇偶性不变
如果操作a c或者a b,那么他们的差还是不变,因为-b -a ,+c,差变化2
所以如果差是奇数没法操作,
再想一下,那么对a的数量有没有啥要求呢
可以发现没要求,
因为b c可以操作自己变出一个a,然后再用 a去操作自己,他们可以独立自主
- #include<bits/stdc++.h>
- using namespace std;
- const int N = 3e5+10,mod= 998244353;
- #define int long long
- int n,m,k;
-
- void solve()
- {
- int a,b,c;
-
-
-
- auto ok=[&](int a,int b,int c)
- {
- int need=abs(b-c);
- if(need%2==0) return true;
- return false;
- };
-
- cin>>a>>b>>c;
-
- if(ok(a,b,c)) cout<<"1 ";
- else cout<<"0 ";
-
- if(ok(b,a,c)) cout<<"1 ";
- else cout<<"0 ";
- if(ok(c,a,b)) cout<<"1 ";
- else cout<<"0 ";
- cout<<"\n";
- }
-
- signed main()
- {
- cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
- int t=1;
- cin>>t;
- while(t--) solve();
- }

C:
感觉很裸的dp
dp状态:通过u这个子树到达叶子节点的最少次数
那么如果是叶子节点无需代价
如果不是叶子节点,判断走的左右子树的方向和当前根方向是否相同,不同代价+1
- #include<bits/stdc++.h>
- using namespace std;
- const int N = 3e5+10,mod= 998244353;
- #define int long long
- typedef long long LL;
- typedef pair<int, char> PII;
-
- int n,m,k;
- string s;
- vector<PII> g[N];
- int f[N];
- void dfs(int u){
- //if(s[u]=='U') f[u]=1;
- if(g[u].empty()){
- f[u]=0;return ;
- }
- for(auto [v,w]:g[u])
- {
- dfs(v);
- f[u]=min(f[u],f[v]+(w!=s[u]));
- }
- }
- void solve()
- {
- cin>>n>>s;
- s="?"+s;
- for(int i=1;i<=n;i++){
- g[i].clear();
- f[i]=2e18;
- }
- for(int i=1;i<=n;i++){
- int a,b;
- cin>>a>>b;
- if(a) g[i].emplace_back(a,'L');
- if(b) g[i].emplace_back(b,'R');
- }
- dfs(1);
- cout<<f[1]<<"\n";
- }
-
- signed main()
- {
- cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
- int t=1;
- cin>>t;
- while(t--) solve();
- }

D:
首先先排序,排序不影响答案
然后问题变成了
当前数(a[i]和前面数的gcd之和)*后面的个数(就是k嘛)
然后难点是前面
我们可以分开求a[x]的因数的贡献,
通过一个调和级数求1到10w的每个数的因子(不是质因子哦,而是因子,比如16的因子有1 2 4 8 16)
然后a[i]和前面数因子的贡献计算
这里举例说明一下
假设
a[i]=20 a[j]=4
a[i]的因子有 1 2 4 510 20
a[j]因子有 1 2 4
那么他们gcd的贡献是gcd(20,4)=4
直接求他们里面最大的共同的的因子不好求(n^2超时间嘛)
但是我们知道每个数的因子最多就128个? n*128够了
然后我们可以求当前数的当前因子能和前面数的因子的总贡献
比如上面例子的1和1配对 2和2配对 4和4配对
但是注意到我们贡献其实只有一个4
那么咋办呢可以用容斥来解决
4的因子里面有2 1
2的因子有1
1的因子只有自己
所以我们求完后还要减去这个因子的倍数
设当前数组f[x]表示因子x有多少个(i,j)的对数
根据上面那个例子a[i]=20 a[j]=4
f[4]=1 f[2]=1 f[1]=1(因为只有两个数嘛,所以只有一对)
然后计算完这个f数组,我们要用容斥减去当前x的倍数的对数
比如上面例子的f[2]要减去f[4] f[1]要减去f[1]减去f[2]减去f[4](这里的f[2]要先减去f[4]哦)
然后当前f[x]数组就是名副其实的因子是x的对数
- #include<bits/stdc++.h>
- using namespace std;
- const int N = 1e5+10,mod= 998244353;
- #define int long long
- typedef long long LL;
- typedef pair<int, char> PII;
-
- int n,m,k;
- int a[N];
- vector<int> g[N];
- int gcd(int a,int b){
- return b?gcd(b,a%b):a;
- }
- void init(){
- for(int i=1;i<N;i++){
- for(int j=i;j<N;j+=i){
- g[j].push_back(i);
- }
- }
- }
- void solve()
- {
- cin>>n;
-
- for(int i=1;i<=n;i++){
- cin>>a[i];
- }
- sort(a+1,a+1+n);
- vector<int> c(N),f(N);
- for(int i=1;i<=n;i++)
- {
- for(auto x:g[a[i]]){
- f[x]+=c[x]*(n-i);
- c[x]++;
- }
- }
- int res=0;
- for(int i=100000;i>=1;i--){
- for(int j=i+i;j<=100000;j+=i){
- f[i]-=f[j];
- }
- res+=f[i]*i;
- }
- cout<<res<<"\n";
- }
-
- signed main()
- {
- cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
- int t=1;
- init();
- cin>>t;
- while(t--) solve();
- }

E:
手完可以发现如果是强联通分量最后会变成一个有向完全图
代表着如果进来了,因为要求路径最长,所以这个强联通分量的点都要走一遍且保证点不重复,
然后直接dp一下即可
然后因为是拓扑序大的 scc_cnt小,因为tarjan是先到底部的,底部的点会先缩,再回溯到上面缩,所以dp直接从1开始即可
- #include<bits/stdc++.h>
- using namespace std;
- const int N = 3e5+10,mod= 998244353;
- #define int long long
- typedef long long LL;
- typedef pair<int, char> PII;
-
- int n,m,k;
-
- vector<int> g[N],h[N];
- int dfn[N],low[N];
- int scc_cnt,timestamp;
- int stk[N],id[N];
- bool in_stk[N];
- int sz[N];
- int top;
- stack<int> s;
- int b[N],a[N],c[N],f[N],gg[N];
- void tarjan(int u){
- dfn[u] = low[u] = ++ timestamp;
- stk[ ++ top] = u, in_stk[u] = true;
- for (auto j:g[u])
- {
-
- if (!dfn[j])
- {
- tarjan(j);
- low[u] = min(low[u], low[j]);
- }
- else if (in_stk[j]) low[u] = min(low[u], dfn[j]);
- }
-
- if (dfn[u] == low[u])
- {
- ++ scc_cnt;
- int y;
- do {
- y = stk[top -- ];
- in_stk[y] = false;
- id[y] = scc_cnt;
- } while (y != u);
- }
-
- }
- void solve()
- {
- cin>>n>>m;
- scc_cnt=timestamp=top=0;
- for(int i=0;i<=n;i++){
- g[i].clear();
- dfn[i]=low[i]=0;
- in_stk[i]=false;
- h[i].clear();
- id[i]=b[i]=c[i]=0;
- f[i]=gg[i]=0;
- }
- for(int i=1;i<=n;i++) cin>>a[i];
-
- for(int i=1;i<=m;i++){
- int a,b;cin>>a>>b;
- g[a].push_back(b);
- }
- for(int i=1;i<=n;i++){
- if(!dfn[i])
- tarjan(i);
- }
-
- for(int i=1;i<=n;i++)
- {
- b[id[i]]+=a[i];
- c[id[i]]++;
- }
- for(int u=1;u<=n;u++){
- //cout<<id[u]<<" ";
- for(auto v:g[u]){
- if(id[u]!=id[v]){
- h[id[u]].push_back(id[v]);
- }
- }
- }
- int ans1=0,ans2;
- for(int i=1;i<=scc_cnt;i++){
- f[i]=c[i],gg[i]=b[i];
- for(auto j:h[i]){
- int t1=f[j]+c[i],t2=gg[j]+b[i];
- if(t1>f[i]||t1==f[i]&&t2<gg[i]){
- f[i]=t1,gg[i]=t2;
- }
- }
- if (f[i] > ans1 || f[i] == ans1 && gg[i] < ans2) ans1 = f[i], ans2 = gg[i];
- }
- cout<<ans1<<" "<<ans2<<"\n";
- }
-
- signed main()
- {
- cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
- int t=1;
- cin>>t;
- while(t--) solve();
- }

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。