Bestcoder #80 题解 (待补)

Lucky

对于一个数字集合S,定义关于S的幸运数字为无法用S中的数相加得到的最小的非负整数(每个数可以使用任意次).

    int T=read();
    while (T--) {
        int n=read();
        bool b=0,b2=0;
        For(i,n) {
            int p=read();
            b|=(p==1);
            b2|=(p==0);
        }
        if (b&&b2) puts("YES");
        else puts("NO");
    }

Segment

x+y=q和坐标轴在第一象限围成了一个三角形,然后画线连接了坐标原点和线段上坐标为整数的格点.
求有多少点在三角形的内部且不是线段或连线上的点,对P取模
q是质数,q,P<=10^18

q是质数,那些后面的连线不会和三角形内部格点相交
pick公式

import java.io.*;
import java.util.*;
import java.math.*;

public class Main
{
    public static void main(String args[])
    {
        Scanner cin = new Scanner(System.in);

        int T=cin.nextInt();  
        while ((T--)>0) {  
            BigInteger q = cin.nextBigInteger();  
            BigInteger P = cin.nextBigInteger(),ans = new BigInteger("1");  
            BigInteger a = q.multiply(q).divide(BigInteger.valueOf(2));
            a = a.add(BigInteger.ONE);
            a = a.subtract(q.multiply(BigInteger.valueOf(3)).divide(BigInteger.valueOf(2)));
            System.out.println(a.mod(P));
        }  
    }
}

Sequence

已知 n ,a, b ,c, p

fn=1,ab,abfcn1fn2,n=1n=2otherwise

1T10,1n1018 , 1a,b,c109 ,p是质数且 p109+7
fn p

两边对a取对数,矩乘快速幂,记得取对数后mod p 变成 mod ϕ(p)
还有a mod p=0时n>=2答案是0,
这时不能用费小,因为gcd(a,p)=p

aφ(n)1(modn)(gcd(a,n)=1)

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<cctype>
#include<ctime>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=next[p])  
#define Lson (x<<1)
#define Rson ((x<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
typedef long long ll;
ll F;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
int read()
{
    int x=0,f=1; char ch=getchar();
    while(!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
    while(isdigit(ch)) { x=x*10+ch-'0'; ch=getchar();}
    return x*f;
} 
#define eps  
#define MAXN (10)
struct M  
{  
    int n,m;  
    ll a[MAXN][MAXN];  
    M(int _n=0){n=m=_n;MEM(a);} 
    M(int _n,int _m){n=_n,m=_m;MEM(a);}
    void mem (int _n=0){n=m=_n;MEM(a);}
    void mem (int _n,int _m){n=_n,m=_m;MEM(a);}

    friend M operator*(M a,M b)  
    {  
        M c(a.n,b.m);  
        For(k,a.m)
            For(i,a.n)  
                For(j,b.m)  
                    c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%F;  
        return c;     
    }  
    friend M operator+(M a,M b)  
    {  
        For(i,a.n)  
            For(j,a.m)  
                a.a[i][j]=(a.a[i][j]+b.a[i][j])%F;  
        return a;
    }  
    void make_I(int _n)  
    {  
        n=m=_n; MEM(a)
        For(i,n) a[i][i]=1;  
    }  
}A,B;
M pow2(M a,ll b)  
{  
    M c;c.make_I(a.n);    
    static bool a2[1000000];    
    int n=0;while (b) a2[++n]=b&1,b>>=1;    
    For(i,n)    
    {    
        if (a2[i]) c=c*a;    
        a=a*a;    
    }    
    return c;    
}

ll pow2(ll a,int b,ll p)  //a^b mod p 
{  
    if (b==0) return 1%p;  
    if (b==1) return a%p;  
    ll c=pow2(a,b/2,p);  
    c=c*c%p;  
    if (b&1) c=c*a%p;  
    return c;  
}  
int main()
{
//  freopen("C.in","r",stdin);
//  freopen(".out","w",stdout);
    int T=read();

    while (T--) {
        ll n,a,b,c;
        cin>>n>>a>>b>>c>>F;
        if (n==1) {
            cout<<1%F<<endl;

        } else if (n==2) {
            cout<<pow2(a,b,F)<<endl;
        } else if (a%F==0) {
            puts("0");
        }else {
            A.mem(3);
            A.a[1][1]=c;
            A.a[1][2]=A.a[2][1]=A.a[3][3]=1;
            A.a[1][3]=b;
            F--; 
            A=pow2(A,n-2);
            ll ans=add(mul(A.a[1][1] , b), A.a[1][3]);
            F++;
            cout<<pow2(a,ans,F)<<endl;
        }
    }
    return 0;
}

Circle

n个同学围成一个圈做约瑟夫游戏,以同学1为起点,开始计数,计数到第k个同学,该同学出圈.出圈的同学将不参与之后的计数.
求已知出圈序列的最小的k

模线性方程,待填坑
考虑2个模线性方程
{X=a0(modm0)X=a1(modm1)
xm0+a0xm0ym1xm0x(m0/g)=ym1+a1=a1a0=a1a0(modm1)=(a1a0)/g(modm1/g)(1)

g=gcd(m0,m1) .
则有解条件为 g|abs(a1a0)
xm0+ym1=gcd(m0,m1)
xm0x(m0/g)xa1a0g(m0/g)=g(modm1)=1(modm1/g)=(a1a0)/g(modm1/g)(2)
对比 (1),(2) ,
x=xa1a0g+k(m1/g),k
X=[xa1a0g+k(m1/g)]m0+a0
X=xa1a0g+a0(mod(m0m1)/g)

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<cctype>
#include<ctime>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=next[p])  
#define Lson (x<<1)
#define Rson ((x<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define PRi(a,n) Rep(i,n-1) cout<<a[i]<<' '; cout<<a[n-1]<<endl;
#define PRi2D(a,n,m) For(i,n) { \
                        For(j,m-1) cout<<a[i][j]<<' ';\
                        cout<<a[i][m]<<endl; \
                        } 
typedef long long ll;
ll F;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
int read()
{
    int x=0,f=1; char ch=getchar();
    while(!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
    while(isdigit(ch)) { x=x*10+ch-'0'; ch=getchar();}
    return x*f;
} 
void gcd(ll a,ll b,ll &d,ll &x,ll &y) {
    if (!b) {d=a,x=1,y=0;   }
    else {gcd(b,a%b,d,y,x); y-=x*(a/b); }
}
// x mod m0=a0,x mod m =a,noSolution return 0 
//初始可令 m0 = 1 ,a0 = 0 
bool china(ll &m0,ll &a0,ll m,ll a)  
{
    ll g,x,y;
    ll c=abs(a-a0);
    gcd(m0,m,g,x,y);
    if ( c % g ) return 0;
    x*=(a-a0)/g; 
    x%=m/g;
    a0=x*m0+a0;
    m0*=m/g;
    a0%=m0;
    if(a0<0) a0+=m0;
    return 1;
}

#define MAXN (1000)
int a[MAXN],h[MAXN];
bool b[MAXN];
int q1[MAXN],m1[MAXN];
int main()
{
//  freopen("D.in","r",stdin);
    int T=read();
    while (T--) {
        int n = read();
        For(i,n) a[i]=read();
        For(i,n) h[a[i]-1]=i-1;
        MEM(b)
        int p=0;
        Rep(i,n)
        {
            m1[i]=n-i;  
            int q=0;
            while(p!=h[i]) {
                q+=(!b[p]);
                p=(p+1)%n; 
            }
            q=(q+1)%m1[i];
            q1[i]=q;    
            b[p]=1;
        }
        ll m0=1,a0=0;
        bool flag=1;
        Rep(i,n) {
            flag=china(m0,a0,m1[i],q1[i]);
            if (!flag) break;
        }
        if (flag) printf("%I64d\n",(!a0)?m0:a0);
        else puts("Creation August is a SB!");
    }


    return 0;
}

Road

n 个地点,m个道路信息,每个道路信息用 (a,b,c,d,w) 表示,意为对任意两个地点 x ,y,满足 axb , cyd ,则在 x ,y两地之间修一条道路,走过这条道路消耗的时间为 w .你可以做k次飞行,每次飞行可以瞬间通过某条已有的路径,从某个点抵达另一个点.
求从 1 号点到n号点消耗的最少时间.
1n5104 , 1m104 , 0k10 , 1w103

待填坑

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这道题是一道典型的费用限制最短路题目,可以使用 Dijkstra 算法或者 SPFA 算法来解决。 具体思路如下: 1. 首先,我们需要读入输入数据。输入数据中包含了道路的数量、起点和终点,以及每条道路的起点、终点、长度和限制费用。 2. 接着,我们需要使用邻接表或邻接矩阵来存储图的信息。对于每条道路,我们可以将其起点和终点作为一个有向边的起点和终点,长度作为边权,限制费用作为边权的上界。 3. 然后,我们可以使用 Dijkstra 算法或 SPFA 算法求解从起点到终点的最短路径。在这个过程中,我们需要记录到每个点的最小费用和最小长度,以及更新每条边的最小费用和最小长度。 4. 最后,我们输出从起点到终点的最短路径长度即可。 需要注意的是,在使用 Dijkstra 算法或 SPFA 算法时,需要对每个点的最小费用和最小长度进行松弛操作。具体来说,当我们从一个点 u 经过一条边 (u,v) 到达另一个点 v 时,如果新的费用和长度比原来的小,则需要更新到达 v 的最小费用和最小长度,并将 v 加入到优先队列(Dijkstra 算法)或队列(SPFA 算法)中。 此外,还需要注意处理边权为 0 或负数的情况,以及处理无法到达终点的情况。 代码实现可以参考以下样例代码: ```c++ #include <cstdio> #include <cstring> #include <queue> #include <vector> using namespace std; const int MAXN = 1005, MAXM = 20005, INF = 0x3f3f3f3f; int n, m, s, t, cnt; int head[MAXN], dis[MAXN], vis[MAXN]; struct Edge { int v, w, c, nxt; } e[MAXM]; void addEdge(int u, int v, int w, int c) { e[++cnt].v = v, e[cnt].w = w, e[cnt].c = c, e[cnt].nxt = head[u], head[u] = cnt; } void dijkstra() { priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q; memset(dis, 0x3f, sizeof(dis)); memset(vis, 0, sizeof(vis)); dis[s] = 0; q.push(make_pair(0, s)); while (!q.empty()) { int u = q.top().second; q.pop(); if (vis[u]) continue; vis[u] = 1; for (int i = head[u]; i != -1; i = e[i].nxt) { int v = e[i].v, w = e[i].w, c = e[i].c; if (dis[u] + w < dis[v] && c >= dis[u] + w) { dis[v] = dis[u] + w; q.push(make_pair(dis[v], v)); } } } } int main() { memset(head, -1, sizeof(head)); scanf("%d %d %d %d", &n, &m, &s, &t); for (int i = 1; i <= m; i++) { int u, v, w, c; scanf("%d %d %d %d", &u, &v, &w, &c); addEdge(u, v, w, c); addEdge(v, u, w, c); } dijkstra(); if (dis[t] == INF) printf("-1\n"); else printf("%d\n", dis[t]); return 0; } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值