ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Codeforces Round #202 (Div. 1)

2022-04-26 20:35:52  阅读:154  来源: 互联网

标签:202 int ll Codeforces long 集合 Div include dp


首先肯定是先找到最大的ai为maxx 答案起码是maxx

发现如果我们按照从大到小依次摆放 只要maxx*(n-1)能容下Σai 那一定能满足(自行模拟一下就好,顺序一定是从大到小)

所以我们只要不断使maxx++ 直到maxx*(n-1)>=Σai就好

#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define ll long long
const int maxn=1e5+5;
ll n,ans;
ll tot,a[maxn];
int main(){
	cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i],tot+=a[i],ans=max(a[i],ans);
	while(1){
		if(ans*(n-1)>=tot){
			cout<<ans;
			return 0;
		}else ans++;
	}
     return 0;
}

这个题看似很简单 确实可以很简单 但是确实也可以难倒人 我就是

开始我的思路一直是从下往上走 却发现根本行不通 索性换个思路 从上往下

假设整棵树的苹果总数为x,我们假设根节点有n棵子树,那么分给每棵子树的苹果数为x/n,并且x一定是n的倍数

利用递归,将子树的苹果平均分给子树的子树。。。

一直到叶子节点,此时我们可以知道,该叶子节点分到的苹果为x的k分之一,因此x为k的倍数,并且x/k不大于该叶子的原来的苹果数

根据这个,我们可以得到一个最小的x; 但要保证x能够均分给每个子树 怎么办?减去 x%所有的lcm 就好

另外,为了避免倍数累乘的时候溢出,当发现k>x时,易知只能将所有的苹果都移掉,直接输出即可。

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
using namespace std;
#define MAXN 100010
typedef long long ll;
int n;
int num[MAXN];
vector<int> G[MAXN];
ll x,sum=0,lcm=1;
ll gcd(ll a,ll b)
{
    return b==0 ? a : gcd(b, a%b);
}

void dfs(int cur=1, ll div=1LL, int fa=-1)
{
    if(div>x)
    {
        cout<<sum;
        exit(0);
        return;
    }
    if(num[cur] || G[cur].size()<=1 && cur!=1) // 是叶子节点
    {
        x=min(x, num[cur]*div);
        lcm=div*lcm/gcd(lcm,div);
        return;
    }
    for(int i=0; i<G[cur].size(); i++)
    {
        if(G[cur][i]!=fa)
            dfs(G[cur][i], div*(ll)(G[cur].size()-1*(cur!=1)),cur);
    }
}
int main()
{
    //freopen("in.txt","r", stdin);

    cin>>n;
    for(int i=1; i<=n; i++)
    {
        scanf("%d", &num[i]);
        sum+=(ll)num[i];
    }
    x=sum;
    for(int i=1; i<=n-1; i++)
    {
        int u,v;
        scanf("%d %d", &u, &v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    dfs();
    cout<<sum-(x-x%lcm);

    return 0;
}

题目还是很好明白 但是思来想去就是想不明白用什么数据结构维护

这个题目思路特别好

为什么要考虑分块?首先想不到合适的数据结构只有暴力

现在有两个问题

1.考虑该集合对其他集合造成的影响

2.该集合当前的Σ是多少

分块的好处在于 考虑 大集合:集合大小 > √集合总数 的集合个数 < √集合总数

              小集合:集合大小 < √集合总数 的集合大小 < √集合总数

这样我们分别对 大集合进行操作1 和 小集合进行操作2 时间复杂度就能保证

不得不说这个题目思路真的好牛

//Subset Sums
#include <cstdio>
#include <cmath>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long lint;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||'9'<ch) {if(ch=='-') f=-1; ch=getchar();}
    while('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int const N=1e5+1e3;
int const N0=400;
int n,m,q,n0; lint a[N];
int ori[N];
struct _set{int siz,id; vector<int> x;} s[N];
bool cmpSiz(_set x,_set y) {return x.siz>y.siz;}
bool tmp[N]; int cnt[N0][N]; lint add[N0],sum[N0];
int main()
{
    n=read(),m=read(),q=read();
    for(int i=1;i<=n;i++) a[i]=read();
    int sumK=0;
    for(int i=1;i<=m;i++)
    {
        s[i].siz=read(),s[i].id=i,s[i].x.push_back(0); sumK+=s[i].siz;
        for(int p=1;p<=s[i].siz;p++) s[i].x.push_back(read());
    }
    sort(s+1,s+m+1,cmpSiz);
    for(int i=1;i<=m;i++) ori[s[i].id]=i;
    n0=sqrt(sumK); int cnt1=0;
    for(int i=1;s[i].siz>=n0;i++) cnt1=i;
    for(int i=1;i<=cnt1;i++)
    {
        memset(tmp,false,sizeof tmp);
        for(int p=1;p<=s[i].siz;p++) sum[i]+=a[s[i].x[p]],tmp[s[i].x[p]]=true;
        for(int j=1;j<=m;j++)
            for(int p=1;p<=s[j].siz;p++) if(tmp[s[j].x[p]]) cnt[i][j]++;
    }
    for(int owo=1;owo<=q;owo++)
    {
        char opt; scanf("%c",&opt);
        if(opt=='?')
        {
            int k=ori[read()];
            if(k<=cnt1) printf("%lld\n",sum[k]);
            else
            {
                lint res=0;
                for(int p=1;p<=s[k].siz;p++) res+=a[s[k].x[p]];
                for(int i=1;i<=cnt1;i++) res+=add[i]*cnt[i][k];
                printf("%lld\n",res);
            }
        }
        if(opt=='+')
        {
            int k=ori[read()]; lint v=read();
            if(k<=cnt1) add[k]+=v;
            else for(int p=1;p<=s[k].siz;p++) a[s[k].x[p]]+=v;
            for(int i=1;i<=cnt1;i++) sum[i]+=v*cnt[i][k];
        }
    }
    return 0;
}

经典的LGV定理 考虑起点为 (1,2)和(2,1) 终点为(n-1,m) 和 (n,m-1)

最后大数据读入要用scanf 我用cin超时了!!!!

#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define ll long long
const int maxn=3e3+5;
const int mod=1e9+7;
int n,m;
ll dp[maxn][maxn][2];
char c[maxn][maxn]; 
int main(){
	cin>>n>>m;
	dp[2][1][0]=dp[1][2][1]=1;
	for(int i=1;i<=n;i++)
	scanf("%s",c[i]+1);
	for(int i=1;i<=n;i++)
	for(int j=1;j<=m;j++){
		if(c[i][j]=='#')continue;
	if(c[i][j-1]=='.'){
		dp[i][j][0]=(dp[i][j][0]+dp[i][j-1][0])%mod;
	    if(j-1>=2)
	    dp[i][j][1]=(dp[i][j][1]+dp[i][j-1][1])%mod;
	}
	if(c[i-1][j]=='.'){
		dp[i][j][1]=(dp[i][j][1]+dp[i-1][j][1])%mod;
		if(i-1>=2)
		dp[i][j][0]=(dp[i][j][0]+dp[i-1][j][0])%mod;
	}
	}
	cout<<(dp[n][m-1][0]*dp[n-1][m][1]%mod+mod-dp[n-1][m][0]*dp[n][m-1][1]%mod)%mod<<endl;
     return 0;
}

标签:202,int,ll,Codeforces,long,集合,Div,include,dp
来源: https://www.cnblogs.com/wzxbeliever/p/16196310.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有