这题是使用了一个total变量持续记录连通块数目,极大减少了判断时间
一开始我直接用从0到n-1遍历找连通块,这样绝对超时
通过代码如下
#include<bits/stdc++.h>
using namespace std;
int fa[400005],q[400005],ans[400005],total;
vector<int> v[400005];
bool vis[400005];
int get(int x){
if(x==fa[x]){
return x;
}
return fa[x]=get(fa[x]);
}
void merge(int x,int y){
fa[get(fa[x])]=get(fa[y]);
}
int main(){
int n,m,t,x,y;
scanf("%d%d",&n,&m);
for(int i=0;i<=n-1;i++){
fa[i]=i;
}
for(int i=0;i<m;i++){
scanf("%d%d",&x,&y);
v[x].push_back(y);
v[y].push_back(x);
}
scanf("%d",&t);
for(int i=0;i<t;i++){
scanf("%d",&x);
q[i]=x;
vis[x]=1;
}
total=n-t;
for(int i=0;i<=n-1;i++){
if(!vis[i]){
for(int j=0;j<v[i].size();j++){
if(!vis[v[i][j]]&&get(i)!=get(v[i][j])){
total--;
merge(i,v[i][j]);
}
}
}
}
ans[t]=total;
reverse(q,q+t);
for(int i=0;i<t;i++){
vis[q[i]]=0;
total++;
for(int j=0;j<v[q[i]].size();j++){
if(!vis[v[q[i]][j]]&&get(q[i])!=get(v[q[i]][j])){
total--;
merge(q[i],v[q[i]][j]);
}
}
ans[i]=total;
}
reverse(ans,ans+t);
for(int i=0;i<=t;i++){
printf("%d\n",ans[i]);
}
return 0;
}
A不了的
1、fa数组没初始化到4e5
2、数组没开大到4e5
3、算法不行
这题还能用图的特殊性质来代替我的vector,但是复杂度是一样的
说能过那是假的
题意很清楚
这题直接先记录Z的数量cntz
然后从头开始
如果是O,cnto++
如果是R ans+=cnto*cntz
如果是Z cntz–
很巧妙
/*
*@Author: STZG
*@Language: C++
*/
#include <bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<bitset>
#include<queue>
#include<deque>
#include<stack>
#include<cmath>
#include<list>
#include<map>
#include<set>
//#define DEBUG
#define RI register int
#define endl "\n"
using namespace std;
typedef long long ll;
//typedef __int128 lll;
const int N=100000+10;
const int M=100000+10;
const int MOD=1e9+7;
const double PI = acos(-1.0);
const double EXP = 1E-8;
const int INF = 0x3f3f3f3f;
int t,n,m,k,p,l,r,u,v;
ll ans,cnt,flag,temp,sum,cot;
char ch[100007];
int main()
{
#ifdef DEBUG
freopen("input.in", "r", stdin);
//freopen("output.out", "w", stdout);
#endif
//ios::sync_with_stdio(false);
//cin.tie(0);
//cout.tie(0);
//scanf("%d",&t);
//while(t--){
scanf("%s",ch);
int len=strlen(ch);
for(int i=0;i<len;i++)
if(ch[i]=='Z')cnt++;
for(int i=0;i<len;i++){
if(ch[i]=='O')cot++;
if(ch[i]=='R')ans+=cot*cnt;
if(ch[i]=='Z')cnt--;
}
printf("%lld\n",ans);
//}
#ifdef DEBUG
printf("Time cost : %lf s\n",(double)clock()/CLOCKS_PER_SEC);
#endif
//cout << "Hello world!" << endl;
return 0;
}
接近凌晨
再写一题
一题挺难想的动态规划
要求在一段序列里寻找两条可不连续的独立的不下降子序列
使得两条序列之和最大
看了几篇博客,都是没讲的很深入
我也想了很久
最后是通过调试想出的这个转移方程的意义
那么首先要明白
既然是两条子序列
我们就要用二维dp
那么以什么为维度呢?
就以每条子序列的 末端!
因为末端好穷举,而且遍历不会漏掉
所以我们的 i 从1开始到n
j从0开始,0代表其中一条序列为空序列
j<i意味着 i永远大于j
就不会重复列举了
此时如果num[i]>num[j]
那么num[i]就具备连接到num[j]后面的条件
然后一个一个链接就好
然后枚举k
总之挺难想的
dp[i][j]意思是两子序列分别以i,j结尾的最大序列之和
#include <bits/stdc++.h>
using namespace std;
int dp[600][600];
int num[600];
int main() {
int n;
scanf("%d",&n);
num[0] = 0;
for (int i=1;i<=n;i++) {
scanf("%d",&num[i]);
}
memset(dp,0,sizeof(dp));
int ans = 0;
for (int i=1;i<=n;i++) {
for (int j=0;j<i;j++) {
if (num[i] >= num[j]) {
for (int k=0;k<i;k++) {
dp[i][k] = max(dp[i][k],dp[j][k] + num[i]);
dp[k][i] = max(dp[k][i],dp[k][j] + num[i]);
ans = max(ans,dp[i][k]);
}
}
}
}
printf("%d\n",ans);
return 0;
}