【总结】10.26.2017 考试总结与解题报告

卷积

(convolution.pas/c/cpp)

【问题描述】

我们先介绍 Dirichlet 卷积
在 算术函数集 上,可以定义一种二元运算,使得取这种运算为乘法,取普通
函数加法为加法,使得 算术函数集 为一个交换环。其中一种这样的运算便是
Dirichlet 卷积。它和一般的卷积有不少相类之处。
对于算术函数 f,g f , g ,定义其 Dirichlet 卷积

(fg)(n)=d|nf(d)g(nd) ( f ∗ g ) ( n ) = ∑ d | n f ( d ) g ( n d )

Dirichlet 卷积有很多美妙的性质:
1. 取 Dirichlet 卷积为运算,积性函数集是算术函数集的 子群
2. 交换律 fg=gf f ∗ g = g ∗ f
3. 结合律 (fg)h=f(gh) ( f ∗ g ) ∗ h = f ∗ ( g ∗ h )
4. 分配律 (f+g)h=fg+fh=h(f+g) ( f + g ) ∗ h = f ∗ g + f ∗ h = h ∗ ( f + g )
5. 存在 单位函数ε 使得 fε=εf f ∗ ε = ε ∗ f 。 ε(n)的值为 1 若 n=1 n = 1 ,否则 ε(n)=0 ε ( n ) = 0
6. 对于任意算术函数 f f ,若f(1) 不等于 0 0 ,都有唯一的 逆函数 f1,使得
ff1=ε f ∗ f − 1 = ε 莫比乌斯函数 μ μ 的 逆函数 为(一般意义上的) 1,即对于
n1,d|nμ(d)×1=0

这是 莫比乌斯反转公式的原理。
这些性质使得 Dirichlet 卷积 在数论中有着特别重要的地位。
现在定义一种运算 有序序列的 Dirichlet 卷积 K K 次自乘,假设原序列为f,结
果序列为 g g ,则有:
g=ff...ff
K K f
现在给出 f f ,我们需要知道fDirichlet 卷积 K K 次自乘

【输入】

输入文件名为 convolution .in,共 2 行。
第一行包含两个正整数N,K
下面一行 N N 个非负整数,第i个数表示 fi f i

【输出】

输出文件名为 convolution .out,共一行,第 i i 个数表示gimod1000000009

【输入输出样例】

输入:

5 2
50 56 85 43 60

输出:

2500 5600 8500 7436 6000

【数据说明】

对于 30%的数据满足, K=1 K = 1 ;

对于100%的数据满足, 1N1e4,1K10,0fi1e5 1 ≤ N ≤ 1 e 4 , 1 ≤ K ≤ 10 , 0 ≤ f i ≤ 1 e 5

题目大意

要是我能总结看懂题目大意,我这题还用骗分

思路

模拟

这可能是我写过的最短的题解了

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define mod 1000000009
#define cl(x) memset(x,0,sizeof(x))
#define rg register

template <typename _Tp> inline void read(_Tp &x){char c11=getchar();x=0;bool booo=0;
    while(c11<'0'||c11>'9'){if(c11=='-')booo=1;c11=getchar();}
    while(c11>='0'&&c11<='9'){x=x*10+c11-'0';c11=getchar();}
    if(booo)x=-x;return ;
}

const int maxn=100020;
ll n,k,f[maxn],d[maxn],now[maxn];

void init();

void work(){
    for(rg int i=1;i<k;++i){
        cl(now);
        for(rg int j=1;j<=n;++j)
        for(rg int l=1;l*j<=n;++l)
            now[l*j]=(now[l*j]+d[j]*f[l])%mod;
        for(rg int j=1;j<=n;++j)d[j]=now[j];
    }
    for(rg int i=1;i<=n;++i)printf("%lld ",d[i]);
}

int main(){
    freopen("convolution.in","r",stdin);
    freopen("convolution.out","w",stdout);
    init();
    work();
    return 0;
}

void init(){
    read(n);read(k);
    for(rg int i=1;i<=n;++i)read(f[i]),d[i]=f[i];
}

巡访

(path.pas/c/cpp)

【问题描述】
Chanxer 终于当上了“中华农民联盟”的盟主,他举目四望,决定四处走走,
巡视自己的农土。
“中华农民联盟”的成员有N个村庄,在“村村通”计划中,村庄们被N − 1条
道路联通了起来,Chanxer 计划从某个村庄出发,访问所有的村庄。
可是 Chanxer 出行有一个特殊的要求,那就是必须以农车代步,现在我们知
道哪些村庄配备有农车,也就是说,只有配备有农车的村庄才能够被作为出发点。
Chanxer 有点懒,他想知道访问全部的村庄所要走的路程长度最小是多少。

【输入】

输入文件名为 path.in,共 N+1 N + 1 行,第一行包含一个正整数 N N
接下来N1行,每行包含三个个整数 xi x i , yi y i , zi z i ,表示 xi x i 号村庄和 yi y i 号村庄之
间有一条长度为 zi z i 的路。
接下来一行包含 N N 个数,每个数不是 0 就是 1 1 ,若第i个数为 1 1 表示可以选择
该点为起始点,否则不可以选。

【输出】
输出文件名为 path.out,共一行,包含一个非负整数,表示最小的路程长度,
若无法访问全部村庄则输出1

【输入输出样例】

输入

5
1 2 1
1 3 1
3 4 3
3 5 4
1 1 1 0 0

输出

12

【数据说明】
6个测试点的数据满足, N10 N ≤ 10 ;
100%的数据满足, N1e5,1xi,yiN,1zi1e4 N ≤ 1 e 5 , 1 ≤ x i , y i ≤ N , 1 ≤ z i ≤ 1 e 4

题目概要

给定一棵边有权值的树,求从给定允许的点中选一点开始遍历,求最小路径

思路

6分解法

puts(“-1”);

24分解法

一看便知树型Dp, g[i] g [ i ] f[i] f [ i ] 分别表示从 i i 这儿出发遍历子树不回来与回来的最小权值数,做n次Dp

100分做法

感性地想一想,一条边最多走两次:去与来

那么我们考虑答案的补集,就是有哪些边不用走两次,由于要遍历一棵树,必须遍历所有边,所以答案转化为求哪些边只走一遍

由于路线必须是连续的(也就是一条链),所以我们又把题目转化为求树上最长链

为什么是最长链呢?

因为要求路径最小,而全集一定,所以要求补集最大,也就是树上最长链

24分树型Dp解法程序

#include<bits/stdc++.h>
using namespace std;
#define inf 2000000050
#define cl(x) memset(x,0,sizeof(x))
#define cl1(x) memset(x,-1,sizeof(x))
#define clm(x) memset(x,0x3f3f3f3f,sizeof(x))
#define rg register

template <typename _Tp> inline void read(_Tp &x){
    char c11=getchar();x=0;
    while(c11<'0'||c11>'9')c11=getchar();
    while(c11>='0'&&c11<='9'){x=x*10+c11-'0';c11=getchar();}return ;
}

const int maxn=100050,maxm=200050;
struct node {int v,w,nxt;} a[maxm];
int head[maxn],p=0;
bool bo[maxn];
int f[maxn],g[maxn];
int ans=inf;
int n;

inline void add(int,int,int);

void init();

void dfs(int x,int las){
    f[x]=0;
    for(rg int i=head[x];i;i=a[i].nxt)if(a[i].v!=las){
        int v=a[i].v,w=a[i].w;
        dfs(v,x);
        f[x]+=w*2+f[v];
    }
    g[x]=f[x];
    int maxx=0;
    for(rg int i=head[x];i;i=a[i].nxt)if(a[i].v!=las)
        maxx=max(maxx,a[i].w+f[a[i].v]-g[a[i].v]);
    g[x]-=maxx;
}

void work(){
    for(rg int i=1;i<=n;++i)
    if(bo[i]){
        dfs(i,0);
        ans=min(ans,g[i]);
    }
    if(ans!=inf)
        printf("%d\n",ans);
    else 
        printf("-1\n");
    return ;
}

int main(){
    freopen("path.in","r",stdin);
    freopen("path.out","w",stdout);
    init();
    work();
    return 0;
}

void init(){
    read(n);
    int A,B,C;
    for(rg int i=1;i<n;++i){
        read(A);read(B);read(C);
        add(A,B,C);add(B,A,C);
    }
    for(rg int i=1;i<=n;++i)read(bo[i]);
}

inline void add(int u,int v,int w){
    a[++p].v=v;
    a[p].w=w;
    a[p].nxt=head[u];
    head[u]=p;
}

大炮

(noligon.pas/c/cpp)

【问题描述】

“农气大炮”是 Chanxer 毕生精力凝结而成的心血。“当大炮建成时,普天之下,莫非农土!”,现在 Chanxer 还有最后一步,就是为大炮装载农气续航系统,换句话说,就是上电池。Chanxer 现在有N条能量棒,第 i 条的长度为 2ki 2 k i ,且拥有一个不稳定值 Wi W i 。为了避免因为单次高强度攻击而导致大炮瘫痪,Chanxer 觉得采用能源分离装置,他准备了许多能量槽,每个能量槽都是条形的,横截面积恰好容得下一根
能量棒插入,而能量槽的深度也为 2t 2 t 的形式。现在,Chanxer 需要再能量棒中选择一些插入能量槽中,为了保证续航时间的最大化,Chanxer 要求每个能量槽都必须完全装满,也就是说,插入其中的能量棒的最长度要正好等于能量槽的深度,与此同时,Chanxer 希望被选择的能量棒的总不稳定值最小。

【输入】

输入文件名为 noligon.in,共 N+M+2 N + M + 2 行。
第一行包含一个整数 N N
接下来 N 行,每行两个整数 ki,Wi k i , W i
接下来一行包含一个整数 M M
接下来M行,每行两个数 t t ,h,表示深度为 2t 2 t 的能量槽有 h h 个。

【输出】

输出文件名为 noligon.out,共一行。
输出一个数表示最小的总不稳定值,假如不存在解就输出1

【输入输出样例】

输入

5
1 3
1 2
3 5
2 1
1 4
2
1 1
2 1

输出

3

【数据说明】
对于30%的数据满足, 1n,m12 1 ≤ n , m ≤ 12 ;
对于100%的数据满足, 1n10000,0ki1,000,0Wi10,000,0t1000,h0,h5000 1 ≤ n ≤ 10000 , 0 ≤ k i ≤ 1 , 000 , 0 ≤ W i ≤ 10 , 000 , 0 ≤ t ≤ 1000 , h ≥ 0 , ∑ h ≤ 5000

题目概要

给定n件物品,m个格子(空间是 2k 2 k 的形式),求填满每个格子的最小花费

思路

10分的’-1’骗分就不说了

直接说正解, 发现它的空间很有特色,是 2k 2 k 的形式,我们凭借幼儿园奥数知识可知,

2k+2k=2k+1 2 k + 2 k = 2 k + 1
那么我们可以将其一步步递推

接下来开始
首先,需知道有没有解:
为了方便描述,记 Numi(i>=0) N u m i ( i >= 0 ) 为尺寸为I的盒子个数; Tii>=0 T i ( i >= 0 ) 为尺寸为I的集装箱个数;
①由于尺寸为0(大小 20 2 0 )的集装箱必须由尺寸为0的盒子来填,所以,如果Num[0]比T[0]小则必定无解,否则能把尺寸为0的集装箱的填满;
②由于尺寸为1(大小21)的集装箱必须由尺寸为0或1的盒子来填,并且只能包含偶数个尺寸为0的组成,而尺寸为0的盒子还剩下Num[0]-T[0]个,这些盒子显然可以两两组合成(Num[0]-T[0])DIV 2个尺寸为1的盒子,故可看作总共有(Num[1]+(Num[0]-T[0])DIV 2)个尺寸为1的盒子,所以Num[1]+ Num[1]+(Num[0]-T[0])DIV 2,Num[0]+0,在按与第一步类似的方法处理即可;
③以此类推;
④若尺寸为0~1000的集装箱都可填满,则必定有解。
然而,增么得到最优解呢?
实际上,只需在求可行解时多加一些运算便可以保证可行解为最优了。
即:1、第k步时,若非无解情况,则选前T[k-1]个价值最小的盒子;
2、第k步时,剩下Num[k-1]-T[k-1]个盒子,则把它从小到大排序后,让第2*I-1与2*I(I>=1)个盒子结合成一个尺寸为k的大盒子。
这样是可以得到最优值。
证明:若存在可行解,而在某一步k中,选的不是前T[k-1]个价值最小的盒子;我们不妨设取了一个价值为b的尺寸为k-1的盒子,且b不是前T[k-1]小的,则必定有一个(或更多)前T[k-1]小的没取,设它的价值为a,显然有b>=a,那我们将原方案中这两个盒子的位子交换一下(若交换前价值为a的这个没有被选,则交换后不选价值为b的这个盒子),就可能得到更优的解(至少不会差),所以,每次都要选价值最小的前几个,而第2步也不难明白:这样组合能使得到的Num[k-1]-T[k-1]DIV 2个盒子的前j(1<=j<=Num[k-1]-T[k-1]DIV 2)小的价值和达到最小,从而使后面的选择也正确。

执行步骤:

1. 读入数据;
2. 分别对不同尺寸的盒子按升序排序,存在value[I]数组中(value[I]中按升序保存所有尺寸为I的盒子的价值);
3. K0,Min0;
4. 若Num[k] < T[k]则转9;
5. 选出value[k]中1到T[k]个盒子,MinMin+value[k,1]+value[k,2] +…value[k,T[k]];
6. 若k<1000,则将剩下的T[k]-Num[k]个盒子,两两组合成(T[k]-Num[k])DIV 2个尺寸为k+1的{第T[k]+1与T[k]+2,T[k]+3与T[k]+4…,组合},在此过程中,把新生成的(T[k]-Num[k])DIV 2归并入value[k+1]中,且Num[k+1]Num[k+1]+ (T[k]-Num[k])DIV 2
7. K:=K+1,若k<=1000转4否则输出Min;
8. 结束
9. 输出无解,转8

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define cl(x) memset(x,0,sizeof(x))
#define rg register

template <typename _Tp> inline void read(_Tp &x){
    char c11=getchar();x=0;
    while(c11<'0'||c11>'9')c11=getchar();while(c11>='0'&&c11<='9'){x=x*10+c11-'0';c11=getchar();}
    return ;
}

const int maxn=10050;
int m[maxn];
int n,ans=0;
priority_queue <ll,vector<ll>,greater<ll> > q[1500];
int maxl=0,M;

void init();

void work(){
    for(rg int i=0;i<=maxl;++i){
        while(m[i]){
            if(q[i].empty()){printf("-1");return ;}
            ans+=q[i].top();q[i].pop();
            --m[i];
        }
        int temp;
        while(!q[i].empty()){
            temp=q[i].top();q[i].pop();
            if(q[i].empty())break;
            q[i+1].push(temp+q[i].top());
            q[i].pop();
        }
    }
    printf("%d\n",ans);
}

int main(){
    freopen("noligon.in","r",stdin);
    freopen("noligon.out","w",stdout);
    init();
    work();
    return 0;
}

void init(){
    read(n);
    cl(m);
    int A,B;
    for(rg int i=1;i<=n;++i){
        read(A);read(B);
        q[A].push(B);
    }
    read(M);
    for(rg int i=1;i<=M;++i){
        read(A);read(B);
        m[A]+=B;
        if(maxl<A)maxl=A;
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据引用中的内容,你所提到的错误信息"ERROR 1045 (28000): Access denied for user 'nvdb'@'10.26.75.16' (using password: YES)" 是MySQL数据库的访问权限错误。这个错误意味着用户'nvdb'在IP地址为'10.26.75.16'的主机上尝试使用密码进行访问时被拒绝了。 根据引用的内容,你可以执行以下步骤来解决这个问题: 1. 确保你输入的用户名和密码是正确的。 2. 确保你的MySQL服务器允许远程访问。你可以检查MySQL服务器配置文件中的bind-address参数是否设置为0.0.0.0,以允许来自任何IP地址的连接。另外,你还需要确保你的防火墙允许从IP地址为'10.26.75.16'的主机访问MySQL服务器的端口。 3. 如果你的MySQL服务器配置了访问控制列表(ACL),你需要确保用户'nvdb'被授权从IP地址为'10.26.75.16'的主机访问数据库。你可以使用命令GRANT来为用户授予适当的权限。 关于插入数据的方式,根据引用的内容,你可以使用以下方式插入数据: 1. 插入完整记录:使用INSERT语句将完整记录一次性插入数据库。 2. 插入记录的一部分:使用INSERT语句指定要插入的字段和对应的值,可以只插入记录的一部分字段。 3. 插入多条记录:使用INSERT语句的多个VALUES子句,每个VALUES子句对应一条记录。 4. 插入另一个查询的结果:使用INSERT INTO SELECT语句,将一个查询的结果插入到另一个表中。 希望这些信息能帮助到你解决问题。如果还有其他问题,请随时提问。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [基于《MySQL5.7从入门到精通》学习记录(20220608_持续更新)](https://blog.csdn.net/jwy19900622/article/details/125176307)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值