NOIP 模拟15

20+25+0+100 寄了,前仨题每道题都只会了一半也是挺厉害的。

A.数字变换

每次操作后 (a+b)modp 的值不变,所以可以先判断 (a+b)modp 是否等于 (c+d)modp,不等的话一定无解。

然后就只需要考虑 a,当 a=c 时就找到了答案。每次可以将 a2amodp 或者 a(ab)modp,后者相当于 (2a(a+b))modp

所以相当于操作 i 次后,a 可以变为 (2iax(ab))modp,x[0,2i1],因为你在第 j 次选择操作二最后会减掉 2ijk,所以相当于每个二进制位都可以分开考虑,所以 x[0,2i1]

使 2iax(ab)c(modp)x(ab+p)2iac(modp),枚举 i 求解不定方程,当最小正整数 x<2ii 就是合法解,当 p2i 次方时一定有解,复杂度 O(qlogp)

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#include<utility>
#include<queue>
#define int long long
using namespace std;
int p,T;
typedef pair<int,int> P;
unordered_map <int,int> h;
int exgcd(int a,int b,int &x,int &y)
{
    if(!b){x=1,y=0;return a;}
    int d=exgcd(b,a%b,y,x);
    y-=(a/b)*x;return d;
}
main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    cin.tie(0),cout.tie(0);
    ios::sync_with_stdio(0);
    cin>>p>>T;
    while(T--)
    {
        int a,b,c,d,k;cin>>a>>b>>c>>d;k=(a+b)%p;
        if((c+d)%p!=(a+b)%p){cout<<"-1\n";continue;}
        if(a==c){cout<<"0\n";continue;}
        for(int i=1;;++i)
        {
            a=a*2%p;int now=(a-c+p)%p;
            int x,y;int d=exgcd(k,p,x,y);
            if(now%d) continue;x=(x*now%p+p)%p;
            if(x<(1<<i)){cout<<i<<'\n';break;}
        }
    }
    return 0;
}

B.均分财产

数据随机,所以直接前 n25 个数依次考虑,当 sum0 时放到第一个集合中,使 sumsum+aisum>0 反之。这样维护出来差值。

然后枚举后 25 个数放到哪个集合中,最后使差值变为 0,由于数据随机所以大概率是可以的,但是我跑的时候需要 random_shuffle。找到解直接跳出,卡时输出 -1

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<time.h>
using namespace std;
const int MAXN=2e5+10;
int n,k,a[MAXN],c[MAXN],pos[MAXN];long long now;
void dfs(int x,long long sum,int k)
{
    if(clock()*1.0/CLOCKS_PER_SEC>0.98) cout<<"-1\n",exit(0);
    if(x>min(n,25))
    {
        if(!sum)
        {
            int cnta=0,cntb=0;
            for(int i=1;i<=n;++i)
            {
                if(c[i]==1) ++cnta;
                if(c[i]==2) ++cntb;
            }
            cout<<cnta<<' ';for(int i=1;i<=n;++i) if(c[i]==1) cout<<pos[i]<<' ';cout<<'\n';
            cout<<cntb<<' ';for(int i=1;i<=n;++i) if(c[i]==2) cout<<pos[i]<<' ';cout<<'\n';
            exit(0);
        }
        return ;
    }
    if(k) c[x]=0,dfs(x+1,sum,k-1);
    c[x]=1,dfs(x+1,sum+a[pos[x]],k);
    c[x]=2,dfs(x+1,sum-a[pos[x]],k);
    return ;
}
int main()
{
    freopen("b.in","r",stdin);
    freopen("b.out","w",stdout);
    cin.tie(0),cout.tie(0);
    ios::sync_with_stdio(0);
    cin>>n>>k;for(int i=1;i<=n;++i) cin>>a[i],pos[i]=i;
    srand(time(0)),rand();random_shuffle(pos+1,pos+1+n);
    if(n<=25) dfs(1,0,k),cout<<"-1\n",exit(0);
    for(int i=26;i<=n;++i)
    {
        if(now<=0) c[i]=1,now+=a[pos[i]];
        else c[i]=2,now-=a[pos[i]];
    }
    dfs(1,now,25),cout<<"-1\n",exit(0);
}

C.查询工资

感觉情况的考虑很复杂,自己不会比题解说的清楚了,不写了。

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int MAXN=8e5+10;
int T,n,k,fa[MAXN],siz[MAXN],f[MAXN];
vector <int> v[MAXN];
inline void clear()
{
    for(int i=1;i<=n;++i) v[i].clear();
    return ;
}
void dfs(int x,int fa=0)
{
    siz[x]=1,f[x]=0;
    int now=0;bool flag=false;
    for(int y:v[x])
    {
        if(y==fa) continue;
        dfs(y,x);siz[x]+=siz[y],f[x]+=f[y];
        if(siz[y]>=k+1) now=max(now,f[y]+1);
        if(!f[y]&&siz[y]>=2) flag=true;
    }
    flag&=(v[x].size()>=k);
    f[x]=max(f[x]+flag,now);return ;
}
inline void work()
{
    cin>>n>>k;
    for(int i=2;i<=n;++i)
        cin>>fa[i],v[fa[i]].push_back(i);
    dfs(1);cout<<f[1]<<'\n';return ;
}
int main()
{
    freopen("c.in","r",stdin);
    freopen("c.out","w",stdout);
    cin.tie(0),cout.tie(0);
    ios::sync_with_stdio(0);
    cin>>T;
    while(T--) work(),clear();
    return 0;
}

D.多项式题

fi 为在 i 处断开,1i 所有情况的乘积的和,S(i,j) 表示 ij 组成的数。

有转移:

fi=j=0i1fj×S(j+1,i)=j=0i1fj×(S(j+1,i1)10+ai)=10×j=0i2fj×S(j+1,i1)+ai×j=0i1fj=10×fi1+ai×j=0i1fj

前缀和优化,O(n)。

#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=2e5+10,MOD=998244353;
int n;long long f[MAXN],a[MAXN],s[MAXN];
int main()
{
    freopen("d.in","r",stdin);
    freopen("d.out","w",stdout);
    cin.tie(0),cout.tie(0);
    ios::sync_with_stdio(0);
    cin>>n;s[0]=1;
    for(int i=1;i<=n;++i)
    {
        char ch;cin>>ch;a[i]=ch-48;
        f[i]=(f[i-1]*10%MOD+s[i-1]*a[i]%MOD)%MOD;
        s[i]=(s[i-1]+f[i])%MOD;
    }
    cout<<f[n]<<'\n';return 0;
}
posted @   int_R  阅读(56)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示