• Codeforces Round #202 (Div. 1)


    首先肯定是先找到最大的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;
    }
    
    
  • 相关阅读:
    100 numpy exercises
    IndentationError: unindent does not match any outer indentation level
    Git详解之七:自定义Git
    Git详解之六:Git工具
    Git详解之五:分布式Git
    Git详解之四:服务器上的Git
    Git详解之三:Git分支
    Git详解之二:Git基础
    Git详解之一:Git起步
    Jquery基础之事件操作
  • 原文地址:https://www.cnblogs.com/wzxbeliever/p/16196310.html
Copyright © 2020-2023  润新知