2023“钉耙编程”中国大学生算法设计超级联赛(4)

Simple Set Problem 尺取,双指针,排序

Data Generation 概率,矩阵快速幂

PSO 期望,签到

Guess  推式子,Pollard-Rho筛素数获得全部因子

Kong Ming Qi 构造

Circuit 最短路计数,弗洛伊德

a-b Problem 贪心,签到

 2023“钉耙编程”中国大学生算法设计超级联赛(4)_第1张图片

 

 首先将全部数字加入集合,数字记录所属集合,从小到大移动左指针,而后右指针在原来基础上向右扩展至第一个满足的即可。取一个最小值

 

# include
using namespace std;
typedef long long int ll;
struct node
{
    int val,id;
};
struct node s[1000000+10];
int cnt[1000000+10];
bool cmp(struct node &x,struct node&y)
{
    return x.val>t;
    while(t--)
    {
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            cnt[i]=0;
        }
        int len=0;
        for(int i=1;i<=n;i++)
        {
            int x;
            cin>>x;
            for(int j=1;j<=x;j++)
            {
                len++;
                cin>>s[len].val;
                s[len].id=i;
            }
        }
        sort(s+1,s+1+len,cmp);
        int ans=2e9+10;
        int pos=0,nowcnt=0;
        for(int i=1;i<=len;i++)
        {
            if(i>=2)
            {
                cnt[s[i-1].id]--;
                if(cnt[s[i-1].id]==0)
                        nowcnt--;
            }
            while(pos<=len&&nowcnt

 2023“钉耙编程”中国大学生算法设计超级联赛(4)_第2张图片

最终答案就是由于每个位置匹配成功的贡献是1,所以最终答案就是n-每个匹配成功的期望。

而每个位置还是相互独立的,所以可以看成n*p[0] 其中p[0]是m次交换之后次成功的期望。

当第i-1次0在自己的位置上时,p[i-1] * ( 1 + (n-1)^2 ) / ( n^2 ),即n^2种交换,只有[0,0]交换,和没有0的交换才能保证0仍然在原位置不懂。

当第i-1次0不在自己的位置上时,( 1-p[i-1] ) * ( 2/(n^2) )

二者综合,可以得出p[i]=(n-2)/n * p[i-1] + 2 / (n^2)

可以用矩阵快速幂解决,但n,m的范围很大,注意对n取模,防止相乘直接爆ll

 

 

#include 
using namespace std;
typedef long long int ll;
# define mod  998244353
ll base[2][2],res[2][2];
void mulans()
{
    ll temp[2][2];
    for(int i=0;i<2;i++)
    {
        for(int j=0;j<2;j++)
        {
            temp[i][j]=0;
        }
    }
    for(int k=0;k<2;k++)
    {
        for(int i=0;i<2;i++)
        {
            for(int j=0;j<2;j++)
            {
                temp[i][j]=(temp[i][j]+res[i][k]*base[k][j]%mod)%mod;
            }
        }
    }
    for(int i=0;i<2;i++)
    {
        for(int j=0;j<2;j++)
        {
            res[i][j]=temp[i][j];
        }
    }
    return ;
}
void mulbase()
{
    ll temp[2][2];
    for(int i=0;i<2;i++)
    {
        for(int j=0;j<2;j++)
        {
            temp[i][j]=0;
        }
    }
    for(int k=0;k<2;k++)
    {
        for(int i=0;i<2;i++)
        {
            for(int j=0;j<2;j++)
            {
                temp[i][j]=(temp[i][j]+base[i][k]*base[k][j]%mod)%mod;
            }
        }
    }
    for(int i=0;i<2;i++)
    {
        for(int j=0;j<2;j++)
        {
            base[i][j]=temp[i][j];
        }
    }
    return ;
}
void qp(ll pow)
{
    for(int i=0;i<2;i++)
    {
        for(int j=0;j<2;j++)
        {
            res[i][j]=0;
            res[i][i]=1;
        }
    }
    while(pow)
    {
        if(pow&1)
            mulans();
        pow>>=1;
        mulbase();
    }
}
ll qsm(ll bas,ll pow)
{
    ll ans=1;
    bas%=mod;
    while(pow)
    {
        if(pow&1)
            ans=ans*bas%mod;
        pow>>=1;
        bas=bas*bas%mod;
    }
    return ans;
}
int main()
{

    int t;
    cin>>t;
    while(t--)
    {
        ll n,m;
        scanf("%lld%lld",&n,&m);
        n%=mod;
        for(int i=0;i<2;i++)
        {
            for(int j=0;j<2;j++)
            {
                base[i][j]=0;
            }
        }
        ll now=((n-2)%mod+mod)%mod*qsm(n,mod-2)%mod;
        ll noww=2ll*qsm(n*n%mod,mod-2)%mod;
        base[0][0]=now;
        base[0][1]=base[1][1]=1;
        qp(m);
        ll ans=(res[0][0]+res[0][1]*noww%mod)%mod;
        ans*=n;
        ans%=mod;
        cout<<((n-ans)%mod+mod)%mod<<'\n';
    }
    return 0;
}

 2023“钉耙编程”中国大学生算法设计超级联赛(4)_第3张图片

 

 其实可以暴力打出前几十个数字的表,发现,只有当n时质数或者n是一个质数的幂的时候,s[n]才不是0

然后利用PR求解即可。

#include
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define fastio ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0)
typedef long long ll;
using namespace std;
const int MOD=998244353;
ll ksm(ll a,ll b,ll p){
    ll ret=1;
    for(;b;b>>=1,a=(__int128)a*a%p)
        if(b&1)ret=(__int128)ret*a%p;
    return ret;
}
bool Miller_Rabin(ll p){
    if(p<2)return 0;
    if(p==2||p==3)return 1;
    ll d=p-1,r=0;
    while(!(d&1))++r,d>>=1;
    for(ll k=0;k<10;++k){
        ll a=rand()%(p-2)+2;
        ll x=ksm(a,d,p);
        if(x==1||x==p-1)continue;
        for(int i=0;i1)return d;
            }
        }
        ll d=__gcd(val,x);
        if(d>1)return d;
    }
}
void solve(ll x){
    if(x<2)return;
    if(Miller_Rabin(x)){
        decom[++tot]=x;
        return;
    }
    ll p=x;
    while(p==x)p=Pollard_Rho(x);
    solve(x/p);solve(p);
}
# define mod 998244353
int main(){
    fastio;
    srand(time(0));
    int T;cin>>T;
    while(T--){
        tot=0;
        ll n;cin>>n;
        assert(1<=n&&n<=(ll)(1e18));
        solve(n);
        sort(decom+1,decom+tot+1);
        tot=unique(decom+1,decom+tot+1)-(decom+1);

        if(tot==1)
        {
            cout<

 2023“钉耙编程”中国大学生算法设计超级联赛(4)_第4张图片

2023“钉耙编程”中国大学生算法设计超级联赛(4)_第5张图片 

 

 

首先有一个构造方案,图中黑点可以消去白点三个,而自己保持不变。根据这一构造,在n>=3的时候,如果m>=3,可以先利用左侧消去将m消三列,留下最后三行的后三列没被消去,利用右侧方案,消去。最终会变成一个n<=3,m<=3的情况

首先n=1||m=1的时候,是对应行列个数除以2向上取整。

n<=3m<=3的时候可以打表出来

#include 
using namespace std;
typedef long long int ll;
int nx[4]={0,0,-1,1};
int ny[4]={1,-1,0,0};
int a[10][10],n,m;
bool check(int x,int y)
{
    return x>=0&&x<=n+1&&y>=0&&y<=m+1;
}
int ans=1e9;
int all;
void work()
{
    int flag=0;

    if(ans==1)
        return ;
    for(int i=0;i<=n+1;i++)
    {
        for(int j=0;j<=m+1;j++)
        {
            if(a[i][j])
            {
                for(int k=0;k<4;k++)
                {
                    int xx=i+nx[k];
                    int yy=j+ny[k];
                    if(check(xx,yy)&&a[xx][yy])
                    {
                        int xxx=xx+nx[k];
                        int yyy=yy+ny[k];
                        if(check(xxx,yyy)&&!a[xxx][yyy])
                        {
                            a[i][j]=0;
                            a[xx][yy]=0;
                            a[xxx][yyy]=1;
                            work();
                            a[i][j]=1;
                            a[xx][yy]=1;
                            a[xxx][yyy]=0;
                            flag=1;
                        }
                    }
                }
            }
        }
    }

    if(flag==0)
    {
        int nowcnt=0;
        for(int i=0;i<=n+1;i++)
        {
            for(int j=0;j<=m+1;j++)
            {
                nowcnt+=(a[i][j]);
            }
        }

        if(nowcnt>t;
    while(t--)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        if(x>y)
            swap(x,y);
        if(x==1)
        {
            cout<<(y+1)/2<<'\n';

        }
        else
        {
            if(x<=4&&y<=4)
            {
                cout<

 

 2023“钉耙编程”中国大学生算法设计超级联赛(4)_第6张图片

有向图计环,在弗洛伊德的时候,转移点k从1枚举到n。考虑对每个环,记录包含[1,1],[1,2],[1,3]...[1,n]的全部环,对于一个包含[1,k]的环,要想不重复的记录,需要以k为起点,这样,包含[1,2]的以2为起点的环,和包含[1,3]以3为起点的环。一定不会重复。又比如,[1,7]的环中,有[4,6],[1,3]。。各种,而[4,6]的环,在[1,6]的时候,已经被以6为起点的记录。 

 

#include
using namespace std;
typedef long long int ll;
ll dis[510][510],cnt[510][510],inf=1e15,edge[510][510];
# define mod 998244353
int main()
{
    cin.tie(0);
    ios::sync_with_stdio(0);
    int t;
    cin>>t;
    while(t--)
    {
        int n,m;
        cin>>n>>m;
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=n; j++)
            {
                dis[i][j]=inf;
                dis[i][i]=0;
                cnt[i][j]=0;
                edge[i][j]=0;
            }
        }
        while(m--)
        {
            int x,y;
            ll val;
            cin>>x>>y>>val;
            dis[x][y]=min(dis[x][y],val);
            edge[x][y]=val;
            cnt[x][y]=1;
        }
        ll minn=1e18,ans=0;
        for(int k=1; k<=n; k++)
        {
            for(int i=1; i<=n; i++)
            {
                for(int j=1; j<=n; j++)
                {
                    if(dis[i][j]==dis[i][k]+dis[k][j])
                    {
                        cnt[i][j]=(cnt[i][j]+cnt[i][k]*cnt[k][j]%mod)%mod;
                    }
                    else if(dis[i][j]>dis[i][k]+dis[k][j])
                    {
                        dis[i][j]=dis[i][k]+dis[k][j];
                        cnt[i][j]=cnt[i][k]*cnt[k][j]%mod;
                    }

                }
            }
            for(int i=1; i=inf)
        {
            cout<<-1<<" "<<-1<<'\n';
            continue;
        }
        cout<

 2023“钉耙编程”中国大学生算法设计超级联赛(4)_第7张图片

 

按照A+B排序的原理是,A+B如果大,要么可以让自己加的分多,要么可以避免对面加更多的分。

# include
using namespace std;
typedef long long int ll;
struct node
{
    int a,b,c;
};
struct node s[100000+10];
bool cmp(struct node &x, struct node &y)
{
    return x.c>y.c;
}
int main()
{
     cin.tie(0);
     ios::sync_with_stdio(0);
     int t;
     cin>>t;
     while(t--)
     {
         int n;
         cin>>n;
         for(int i=1;i<=n;i++)
         {
             cin>>s[i].a>>s[i].b;
             s[i].c=s[i].a+s[i].b;
         }
         sort(s+1,s+1+n,cmp);
         ll sum1=0,sum2=0;
         for(int i=1;i<=n;i++)
         {
             if(i%2)
             {
                 sum1+=s[i].a;
             }
             else
             {
                 sum2+=s[i].b;
             }
         }

         cout<

 

你可能感兴趣的:(多校真题,算法,ICPC,区域赛)