2022/5/5

Breaking the Wall

瞟了一眼题解知道是分类讨论后就开始自己找情况,第一种是两个数中间隔着一个数,这样的就需要较小数加上较大数减去较小数除以2;第二种是整个数组的最小值/2+次小值/2;第三种是相邻的两个数,一开始想的是(a[i]+a[i+1])/3向上取整就可以了,但是被1 10这个数据给卡了,然后就卡死了,其实只要比较一下a[i]/2,a[i+1]/2,(a[i]+a[i+1])/3取最大值就可以了,这样就包含了所有情况;

Codeforces Round #786 (Div. 3) E(分类讨论) F(模拟) G(树上dp) - 知乎 (zhihu.com)

#include
#define ll long long
#define lowbit(i) ((-i)&(i))
using namespace std;
const ll inf=1e18;
const ll mod=998244353;
ll n;
double a[200005];
int main(){
	//freopen("in.txt","r",stdin);
	scanf("%lld",&n);
	for(int i=1;i<=n;i++) scanf("%lf",&a[i]);
	double min1=inf,min2=inf;
	ll ans=inf;
	a[n+1]=a[0]=1e9;
	for(int i=1;i<=n;i++){
        ans=min(ans,max({(ll)ceil((a[i]+a[i+1])/3),(ll)ceil(a[i]/2),(ll)ceil(a[i+1]/2)}));
        ans=min(ans,(ll)min(a[i-1],a[i+1])+(ll)(ceil((max(a[i-1],a[i+1])-min(a[i-1],a[i+1]))/2)));
        if(min1>a[i]){
            min2=min1;min1=a[i];
        }
        else if(min2>a[i]){
            min2=a[i];
        }
	}
	ans=min(ans,(ll)ceil(min1/2)+(ll)ceil(min2/2));
	printf("%lld\n",ans);
	return 0;
}

Desktop Rearrangement

这题竟然让我用树状数组玩出来了(但大佬的题解做法好像很简单,,,),虽然说一开始题意都没读懂,,,题意就是用已有的*去一列一列的填充问需要至少移动多少个*才能达到把列填充完的效果,也就是如下图这样

2022/5/5_第1张图片

图是这个大佬的Codeforces Round #786 (Div. 3) E(分类讨论) F(模拟) G(树上dp) - 知乎 (zhihu.com) 

 思路很直接,我们先确定有多少个*,然后看看这些*能排到第几列的什么位置,假设位置为(x,y),然后从(1,1)开始一列一列的遍历,遍历到(x,y)看看经过了多少*,答案就是一共*的个数减去经过*的个数,但这样遍历会超时,反正是一列一列的遍历,那我们把这个矩阵拉成一条链也不影响遍历,直接转化为一维数组,这样再去查询*的个数就好求了,直接使用树状数组就行,树状数组维护前i个位置有多少*,查询时直接ask(cnt),答案就是cnt-ask(cnt);

#include
#define ll long long
#define lowbit(i) ((-i)&(i))
using namespace std;
const ll inf=1e18;
const ll mod=998244353;
ll n,m,q,cnt;
char a[1005][1005],c[1000006];
ll t[1000006];
void add(ll x,ll y){
    for(int i=x;i<=n*m;i+=lowbit(i))
        t[i]+=y;
}
ll ask(ll x){
    ll res=0;
    for(int i=x;i;i-=lowbit(i))
        res+=t[i];
    return res;
}
int main(){
	//freopen("in.txt","r",stdin);
	scanf("%lld%lld%lld",&n,&m,&q); cnt=0;
	for(int i=1;i<=n;i++) scanf("%s",a[i]+1);
	for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++){
            c[(i-1)*n+j]=a[j][i];
            if(a[j][i]=='*') add((i-1)*n+j,1),cnt++;
    }
    while(q--){
        ll x,y;
        scanf("%lld%lld",&x,&y);
        if(c[(y-1)*n+x]=='*') c[(y-1)*n+x]='.',add((y-1)*n+x,-1),cnt--;
        else c[(y-1)*n+x]='*',add((y-1)*n+x,1),cnt++;
        printf("%lld\n",cnt-ask(cnt));
    }
	return 0;
}

Remove Directed Edges

有向无环图删除一些边使得所有点的入度和出度都减少,一开始就为0的话不用管,既然是无环图那最后的结果一定不会有这种情况2022/5/5_第2张图片

(图片来自同一位大佬),这样下面的两个点没有联系不符合条件,所以只有可能是链,所以这问题就变成了求树的一个最长链,但是得加些限制,出度小于2的不能去遍历子节点,入度小于2的不能向父节点转移 ;

Codeforces Round #786 (Div. 3) E(分类讨论) F(模拟) G(树上dp) - 知乎 (zhihu.com)

#include
#define ll long long
#define lowbit(i) ((-i)&(i))
using namespace std;
const ll inf=1e18;
const ll mod=998244353;
ll n,m,dp[200005],in[200005],ans,out[200005];
vectorv[200005];
void dfs(ll u){
    if(dp[u]) return;
    dp[u]=1;
    if(out[u]<=1) return;
    for(int i=0;i=2) dp[u]=max(dp[u],dp[j]+1);
    }
    ans=max(ans,dp[u]);
}
int main(){
	//freopen("in.txt","r",stdin);
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=m;i++){
        ll u,vv;
        scanf("%lld%lld",&u,&vv);
        v[u].push_back(vv);
        in[vv]++;out[u]++;
	}
	ans=1;
	for(int i=1;i<=n;i++) dfs(i);
	printf("%lld\n",ans);
	return 0;
}

你可能感兴趣的:(笔记,算法,c++,蓝桥杯,c++,算法)