AGC 018

A
发现组合出的数一定比最大的ai小,且一定是gcd的倍数(可以构造出gcd)

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

const int maxn = 110000;

int gcd(int a,int b){return a==0?b:gcd(b%a,a);}

int n,k;
int a[maxn];

int main()
{
    scanf("%d%d",&n,&k);
    int d=0,mx=0;
    for(int i=1;i<=n;i++) 
    {
        scanf("%d",&a[i]);
        d=gcd(d,a[i]); if(a[i]>mx) mx=a[i];
        if(a[i]==k) { puts("POSSIBLE");return 0; }
    }
    if(mx>k&&k%d==0) puts("POSSIBLE");
    else puts("IMPOSSIBLE");    

    return 0;
}

B
对于选出一些活动的状态,瓶颈是最大人数的活动x,而要减少最大人数,要么选出新的活动使得x的参加人数减少,要么去掉x
我们先选出所有活动,此时最大人数的活动x,不能再添加活动使其减少,若要答案更优,一定要去掉x,所以去寻找不含x的情况下的最优解,递归下去,复杂度nm^2

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

const int maxn = 310;

int n,m;
int a[maxn][maxn];

bool v[maxn];
int ans;
int d[maxn];
void solve(const int num)
{
    if(num==1) return;
    for(int i=1;i<=m;i++) d[i]=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++) if(v[a[i][j]])
        {
            d[a[i][j]]++;
            break;
        }
    }
    int now=0;
    for(int i=1;i<=m;i++) if(d[i]>d[now]) now=i;
    if(ans>d[now]) ans=d[now];
    v[now]=false;
    solve(num-1);
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++) scanf("%d",&a[i][j]);
    }
    for(int i=1;i<=m;i++) v[i]=true;
    ans=n;
    solve(m);
    printf("%d\n",ans);

    return 0;
}

C
因为每个人一定被某种类型选到,我们知道了X+Y个数是哪些,就知道剩下Z个数是哪些,所以我们可以转化模型,将(A,B,C)变成(A-C,B-C,C),变成在X+Y+Z个数中选X个数取它的A,Y个数取它的B,和的最大值再加上C。
假设我们选出了X+Y个数,我们将他们和没被选出的数一起按照a-b排序,发现对于两组数i(a,b,c),j(A,B,C),(i< j)有a-b<=A-B -> a+B<=A+b,即我们选的X个数一定在Y个数右边(如果有在左边的,交换位置不会变劣)
可以用堆搞出prei,sufi,枚举断点找最大值

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define inf 1e12
using namespace std;

const int maxn = 110000;

int X,Y,Z,n;
ll a[maxn],b[maxn],c[maxn];
bool v[maxn];
struct node{ll a,b,c;}s[maxn];
inline bool cmpc(const node x,const node y){return x.c<y.c;}

ll ans;
ll pre[maxn],suf[maxn];
struct E{ll x;};
inline bool operator <(const E x,const E y){return x.x>y.x;}
priority_queue<E>q;

int main()
{
    scanf("%d%d%d",&X,&Y,&Z); n=X+Y+Z;
    for(int i=1;i<=n;i++)
    {
        scanf("%lld%lld%lld",&a[i],&b[i],&c[i]); ans+=c[i];
        s[i]=(node){a[i]-c[i],b[i]-c[i],a[i]-b[i]};
    }
    sort(s+1,s+n+1,cmpc);

    for(int i=1;i<=n;i++)
    {
        pre[i]=pre[i-1];
        if(i>Y)
        {
            if((q.top()).x<s[i].b) 
                pre[i]-=(q.top()).x,q.pop(),pre[i]+=s[i].b,q.push((E){s[i].b});
        }
        else pre[i]+=s[i].b,q.push((E){s[i].b});
    }pre[0]=-1e12;
    while(!q.empty()) q.pop();
    for(int i=n;i>=1;i--)
    {
        suf[i]=suf[i+1];
        if(n-i>=X)
        {
            if((q.top()).x<s[i].a)
                suf[i]-=(q.top()).x,q.pop(),suf[i]+=s[i].a,q.push((E){s[i].a});
        }
        else suf[i]+=s[i].a,q.push((E){s[i].a});
    }suf[n+1]=-1e12;
    ll now=LLONG_MIN;
    for(int i=1;i<=n;i++) if(i>=Y&&n-i>=X)
    {
        ll temp=pre[i]+suf[i+1];
        if(temp>now) now=temp;
    }
    ans+=now;
    printf("%lld\n",ans);

    return 0;
}

D
考虑每条边对答案的贡献,假设它连接的两个联通块较小的size是s,如果是哈密顿回路,它的贡献最大为 2cs
在树有双重心的情况下,我们一定能构造一个回路使得每条边的贡献达到最大(在左右两个重心的子树内交替跳),这时我们要考虑对于哈密顿回路上的相邻点u,v,删掉u,v路径上的边权和,我们发现对于双重心x,y之间的边(x,y),当且仅当上文的构造回路方法能使得它被经过n次,其他情况最多只有n-1次,此时回路上的任意相邻点都不在一棵重心的子树上,怎么删都一定会删掉这条边,所以这条边被经过的上界是n-1,而我们有一种方法构造使得回路变路径只需要删掉这条边(x为路径的出发点,y为终点,2棵子树交替跳),所以 2cs(x,y) 就是最优解
对于树重心 G 唯一的情况,类似的,和重心相连的边中一定有一条经过次数不能达到2s,且我们用与上文类似的构造一种方案使得只需要删掉这条边,那么 2csmin(G,v) 就是最优解

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define inf 1e9
using namespace std;

inline void down(int &x,const int &y){if(x>y)x=y;}
const int maxn = 210000;

int n,m;
struct edge{int y,c,nex;}a[maxn]; int len,fir[maxn];
inline void ins(const int x,const int y,const int c){a[++len]=(edge){y,c,fir[x]};fir[x]=len;}

int siz[maxn],rt,uc[maxn];
void dfs(const int x,const int fa)
{
    bool flag=true; siz[x]=1;
    for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y) if(y!=fa)
    {
        uc[y]=a[k].c; dfs(y,x); siz[x]+=siz[y];
        if(siz[y]*2>n) flag=false;
    }
    if((n-siz[x])*2>n) flag=false;
    if(flag) rt=x;
}

ll ans;

int main()
{
    scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        int x,y,c; scanf("%d%d%d",&x,&y,&c);
        ins(x,y,c); ins(y,x,c);
    }
    dfs(1,0);
    for(int i=1;i<=n;i++) ans+=uc[i]*2ll*min(siz[i],n-siz[i]);
    int rt2=-1;
    for(int k=fir[rt],y=a[k].y;k;k=a[k].nex,y=a[k].y)
    {
        if(siz[y]>siz[rt])
        {
            if(siz[rt]*2<=n) rt2=y;
        }
        else if((n-siz[y])*2<=n) rt2=y;
    }
    if(rt2==-1)
    {
        int mc=inf;
        for(int k=fir[rt],y=a[k].y;k;k=a[k].nex,y=a[k].y) down(mc,a[k].c);
        ans-=(ll)mc;
    }
    else
    {
        for(int k=fir[rt],y=a[k].y;k;k=a[k].nex,y=a[k].y) if(y==rt2)
            ans-=(ll)a[k].c;
    }
    printf("%lld\n",ans);

    return 0;
}

E
我们定义f(x,y)表(0,0)到(x,y)的方案数,有 xi=0f(i,y)=f(x+1,y) (枚举最后一条竖边的位置)
从而 xi=0yj=0f(i,j)=f(x+1,y+1)1 (横着用一次,竖着用一次第一条柿子)
于是有
dxi=sxdyj=syf(i,j)=f(dx+1,dy+1)f(sx,dy+1)f(dx+1,sy)+f(sx,sy)
可以发现一个点到一个矩阵内任意点的方案数只和其到4个点的带权方案数相关,反之亦然。

我们先忽略矩阵B,矩阵A到矩阵C的方案数=矩阵A到4个带权点方案数=4个点到4个点的带权方案数。
接着考虑中间矩阵B(这部分看代码更好懂?),一条路径要乘上它和矩阵B的交点个数,而交点个数其实只和进出点相关,贡献是 k=(dx+dysxsy+1) ,然后我们把 dxdy sxsy 拆开来算贡献,枚举矩阵B的四条边,左下是入点,右上是出点,分开计算贡献

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define inf 1e9
using namespace std;

const int maxn = 2100000;
const ll Mod = 1e9+7;

ll pw(ll x,int k)
{
    ll re=1ll;
    for(;k;k>>=1,x=x*x%Mod) if(k&1)
        re=re*x%Mod;
    return re;
}

ll s[maxn],pinv[maxn];
void pre()
{
    s[0]=1ll;
    for(ll i=1;i<maxn;i++) s[i]=s[i-1]*i%Mod;
    pinv[maxn-1]=pw(s[maxn-1],Mod-2);
    for(ll i=maxn-2;i>=0;i--) pinv[i]=pinv[i+1]*(i+1ll)%Mod;
}
ll C(const int i,const int j){return s[i]*pinv[j]%Mod*pinv[i-j]%Mod;}

int x[6],y[6];
struct node{int x,y;ll v;}a[4],b[4];
ll cal(const node x,const node y){return C(y.x+y.y-x.x-x.y,y.x-x.x);}

ll ans;

int main()
{
    pre();
    for(int i=0;i<6;i++) scanf("%d",&x[i]);
    for(int i=0;i<6;i++) scanf("%d",&y[i]);

    a[0]=(node){x[0]-1,y[0]-1,1ll};
    a[1]=(node){x[0]-1,y[1],-1ll};
    a[2]=(node){x[1],y[0]-1,-1ll};
    a[3]=(node){x[1],y[1],1ll};

    b[0]=(node){x[4],y[4],1ll};
    b[1]=(node){x[4],y[5]+1,-1ll};
    b[2]=(node){x[5]+1,y[4],-1ll};
    b[3]=(node){x[5]+1,y[5]+1,1ll};

    ans=0;
    for(int i=0;i<4;i++) for(int j=0;j<4;j++)
    {
        ll now=0;
        for(int k=y[2];k<=y[3];k++) 
            (now+=(ll)(-x[2]-k+1)*cal(a[i],(node){x[2]-1,k})%Mod*cal((node){x[2],k},b[j])%Mod)%=Mod;
        for(int k=x[2];k<=x[3];k++) 
            (now+=(ll)(-k-y[2]+1)*cal(a[i],(node){k,y[2]-1})%Mod*cal((node){k,y[2]},b[j])%Mod)%=Mod;
        for(int k=y[2];k<=y[3];k++) 
            (now+=(ll)(k+x[3])*cal(a[i],(node){x[3],k})%Mod*cal((node){x[3]+1,k},b[j])%Mod)%=Mod;
        for(int k=x[2];k<=x[3];k++) 
            (now+=(ll)(k+y[3])*cal(a[i],(node){k,y[3]})%Mod*cal((node){k,y[3]+1},b[j])%Mod)%=Mod;
        ans+=now*a[i].v*b[j].v%Mod;
    }
    printf("%lld\n",(ans%Mod+Mod)%Mod);

    return 0;
}

F
每棵子树的和都为1或-1,都是奇数
如果一个点x有奇数个孩子,则它的权一定为偶,有偶数个孩子则它的权一定为奇,若它在2棵树内的奇偶性不同则一定无解,否则有2种方法构造出解:

author’s solution:
新建一个图,每个点在A、B树的点为x,x’,若x的度数为奇(偶数个孩子),x和x’连边,两棵树内的边照连,新建一个点G和A,B树的根连边,此时每个点度数都为偶数,一定存在一个欧拉回路。
对于一个奇数点,如果它在欧拉回路中由x->x’,他的权为1,否则为-1,对于任意子树,进入子树内的次数=离开子树内的次数,其中进入或离开有1次是走树边,易知子树和一定是1或-1

admin’s solution:
两棵树分别考虑,对于每棵子树,里面的2K+1个奇数点匹配成2K对,我们令每对点一个为1,一个为-1,就能使每个子树权都为1或-1。
新建一个图,对于A树中的配对(x,y),连红边,B树中的配对(x,y),连蓝边,对于新图中的环,一定是红蓝边交错的(一个点不可能匹配两个点所以不可能有相连的同颜色边),所以新图不存在奇环,一定是二分图,所以一定能构造出一组解

(我写了第二种的因为好写233)
code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

const int maxn = 210000;

int n,m;
vector<int>V[maxn];
struct edge{int y,nex;}a[maxn]; int len,fir[maxn];
inline void ins(const int x,const int y){a[++len]=(edge){y,fir[x]};fir[x]=len;}

int rt,d[maxn],d2[maxn];
int v[maxn],oth[maxn];
int t[maxn],tp;
void dfs(const int x)
{
    for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y) dfs(y);
    tp=0;
    for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y) t[++tp]=oth[y];
    for(int i=2;i<=tp;i+=2)
    {
        int x=t[i-1],y=t[i];
        V[x].push_back(y); V[y].push_back(x);
    }
    if(d[x]&1) oth[x]=t[tp];
    else oth[x]=x;
}
void col(const int x)
{
    for(int i=0;i<V[x].size();i++)
    {
        const int y=V[x][i];
        if(v[y]==2) v[y]=-v[x],col(y);
    }
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        int x; scanf("%d",&x);
        if(x==-1) rt=i;
        else ins(x,i),d[x]++;
    }
    dfs(rt);

    memset(fir,0,sizeof fir); len=0;
    for(int i=1;i<=n;i++)
    {
        int x; scanf("%d",&x);
        if(x==-1) rt=i;
        else ins(x,i),d2[x]++;
    }
    for(int i=1;i<=n;i++) if((d[i]&1)!=(d2[i]&1)) { puts("IMPOSSIBLE");return 0; }
    for(int i=1;i<=n;i++) if(!(d[i]&1)) v[i]=2;
    dfs(rt);

    for(int i=1;i<=n;i++) if(v[i]==2) v[i]=1,col(i);
    puts("POSSIBLE");
    for(int i=1;i<=n;i++) printf("%d ",v[i]);

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Matlab中,AGC(Automatic Gain Control)是一种用于自动调节信号增益的技术AGC系统的作用是保持信号在一个适当的功率范围内,以便有效地处理和分析信号。使用Matlab可以实现数字AGC系统的建模与仿真。 在Matlab中使用Simulink环境进行数字AGC的建模与仿真可以通过以下步骤实现: 1. 使用Simulink库中的信号源模块生成输入信号。可以使用随机信号或特定模式的信号作为输入。 2. 将信号传递到AGC模块,该模块可以从Simulink库中选择或自定义。 3. 配置AGC模块的参数,例如增益平均系数、增加步进、减小步进、参考级别、上限和下限等。 4. 将AGC模块的输出与其他模块连接,例如显示模块或数据处理模块。 5. 运行模型并观察AGC系统的输出结果。 通过以上步骤,您可以使用Matlab中的Simulink环境建立数字AGC模型,并使用Matlab实现数字AGC系统。需要注意的是,在实际应用中,数字AGC系统的复杂程度可能会更高,需要根据具体情况进行调整和优化。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [基于Simulink的数字AGC建模与仿真](https://blog.csdn.net/CodeWG/article/details/130591628)[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_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值