zoukankan      html  css  js  c++  java
  • 2020 SWJTU-ICPC Training Round #2(18年福建省赛)部分题解

    A-Uint47 calculator(快速乘)

    题意:

    定义一堆变量然后进行加减乘除运算

    思路:

    这题难的地方在乘法,会超出long long的范围,所以要用到快速乘(原理跟快速幂类似)

    #include<iostream>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<string>
    #define Endl endl
     using namespace std;
     typedef long long ll;
     const ll mod=1ll<<47;
     map<string,ll> m;
     string s1,s2,s3;
     ll qm(ll a,ll b)
     {
         ll ans=0;
         while(b){
             if(b%2) ans=(ans+a)%mod;
            a=(a+a)%mod;
            b/=2;
         }
        return ans;
     }
     int main()
     {
         ll num;
         while(cin>>s1>>s2){
             if(s1=="def") cin>>num;
             else{
                 cin>>s3;
                 if(s1=="add") num=(m[s2]+m[s3])%mod;
                 if(s1=="sub") num=(m[s2]-m[s3]+mod)%mod;
                 if(s1=="mul") num=qm(m[s2],m[s3]);
                 if(s1=="div") num=m[s2]/m[s3];
                 if(s1=="mod") num=m[s2]%m[s3];
             }
             if(num<0) num+=mod;
             m[s2]=num;
             cout<<s2<<" = "<<num<<endl;
         }
         return 0;
     }
    View Code

    D-Number theory(线段树)

    题意:

    初始化x=1,有两种操作:M yi: x = x * y 与  N di: x = x / ydi ,输出每次操作之后的x的值

    思路:

    用线段树维护乘积和,线段树下标对应的值就为yi

    每次进行M操作时将yi进行修改,N操作则将对应的ydi修改为1,每次修改输出Tree[1]即为乘积

    #include<iostream>
    #include<algorithm>
     using namespace std;
     typedef long long ll;
     const int maxn=1e5+20;
     ll tree[maxn<<2],m;
     void push_up(int rt)
     {
         tree[rt]=(tree[rt<<1]*tree[rt<<1|1])%m;
     }
     void update(int pos,int l,int r,int val,int rt)
     {
         if(l==r){
             tree[rt]=val;
             return;
         }
        int mid=(l+r)>>1;
        if(pos<=mid) update(pos,l,mid,val,rt<<1);
        else update(pos,mid+1,r,val,rt<<1|1);
        //push_up(rt);
        tree[rt]=(tree[rt<<1]*tree[rt<<1|1])%m;
     }
     int main()
     {
         int t,k,n;
         char s[9];
         scanf("%d",&t);
         while(t--){
             scanf("%d%lld",&n,&m);
             for(int i=1;i<=n<<2;i++) tree[i]=1;
             for(int i=1;i<=n;i++){
                 scanf("%s%d",&s,&k);;
                 if(s[0]=='M') update(i,1,n,k,1);
                 else  update(k,1,n,1,1);
                 cout<<tree[1]<<endl;
             }
         }
     }
    View Code

    E-Traffic jam(最短路)

    题意:

    给一张无向图带权图,每个点在每个特定时段才能通行,从点s到点t的最短时间

    思路:

    正常跑dij,在进行松弛操作时,要判断点能否通行,不能通行的话边权要加上等待的时间之后看看能否松弛

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #define inf 0x3f3f3f3f
     using namespace std;
     const int maxn=1005;
     int dis[maxn],m[maxn][maxn],a[maxn],vis[maxn];
     int t,n,k,u,v,val,x,y;
     void init()
     {
         memset(vis,0,sizeof(vis));
         memset(dis,inf,sizeof(dis));
         memset(m,inf,sizeof(m));
         for(int i=1;i<=n;i++) m[i][i]=0;
     }
     int dij(int s,int t)
     {
         dis[s]=0;
         //vis[s]=1;
         for(int i=1;i<=n;i++){
             int temp=-1,mx=inf;
             for(int j=1;j<=n;j++){
                 if(!vis[j]&&dis[j]<mx){
                     temp=j;
                     mx=dis[j];
                 }
             }
            if(t==-1) break;
            vis[temp]=1;
            for(int j=1;j<=n;j++){
                if(!vis[j]&&m[temp][j]!=inf){
                    int d=dis[temp];
                    if((d%(2*a[temp]))>=a[t])
                        d+=(a[temp]-d%a[temp]);
                    d=d+m[temp][j];
                    if(dis[j]>d)
                        dis[j]=d;
                }
            }
         }
         return dis[t];
     }
     int main()
     {
         scanf("%d",&t);
         while(t--){
             scanf("%d%d",&n,&k);
             init();
             for(int i=1;i<=n;i++) scanf("%d",&a[i]);
             for(int i=1;i<=k;i++){
                 scanf("%d%d%d",&u,&v,&val);
                 m[u][v]=m[v][u]=val;
             }
            scanf("%d%d",&x,&y);
            cout<<dij(x,y)<<endl;
         }
        return 0;
     }
    View Code

    G-IoU(思维)

    题意:

    给两个矩形,问他们重叠部分的面积占合并之后的图形的面积的比值

    思路:

    直接求出合并之后的面积再减去原来两矩形的面积就为重叠的面积,注意要判断两个矩形是否重合

    #include<iostream>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<string>
    #define Endl endl
     using namespace std;
     typedef long long ll;
     int main()
     {
         ll Cas,x1,x2,y1,y2,w1,w2,h1,h2,x3,y3,x4,y4;
         ll s,s1,s2;
         double rate;
         scanf("%lld",&Cas);
         while(Cas--){
             cin>>x1>>y1>>w1>>h1;
             cin>>x2>>y2>>w2>>h2;
             x3 = max(min(x1,x1+w1),min(x2,x2+w2)); 
            y3 = max(min(y1+h1,y1),min(y2,y2+h2));  
            x4 = min(max(x1,x1+w1),max(x2,x2+w2));
            y4 = min(max(y1+h1,y1),max(y2,y2+h2));
            if(x4>x3&&y4>y3) s=(y4-y3)*(x4-x3);
            else s=0;
            s1=w1*h1,s2=w2*h2;
            rate=(s*1.0)/(1.0*(s2+s1-s));
            printf("%.2lf
    ",rate);
         }
        return 0;
     }
    View Code

    H-Chosen by god(组合数学)

    题意:

    进行n次攻击,每次攻击随机并等可能对敌人或敌人的侍从造成1单位伤害,敌人的血量无限,侍从的血量为m,问杀死侍从的概率是多少

    思路:

    进攻n次总共会有2n种可能,要杀死侍从至少要对其进攻m次,所以如果n<m,则概率为0

    能杀死侍从的概率就有C(n,m)+C(n,m+1)+.....+C(n,n)种

    所以概率就为C(n,m)+C(n,m+1)+.....+C(n,n)/2n

    #include<iostream>
    #include<algorithm>
     using namespace std;
     typedef long long ll;
     const int mod=1e9+7;
     const int maxn=1e3+10;
     ll C[maxn][maxn];
     ll pm(ll a,ll b)
     {
         ll ans=1;
         while(b){
             if(b&1) ans=(a*ans)%mod;
             a=(a*a)%mod;
             b>>=1;
         }
        return ans;
     }
     ll get_C()
     {
         C[0][0]=1;
         for(int i=0;i<maxn;i++){
             C[i][0]=C[i][i]=1;
             for(int j=1;j<=i;j++)
                 C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
         }
     }
     int main()
     {
         get_C();
         int Cas,n,m;
        ll ans,x;
         scanf("%d",&Cas);
         while(Cas--){
             ans=0;
             scanf("%d%d",&n,&m);
            for(int i=m;i<=n;i++){
                ans+=C[n][i];
                ans%=mod;
            }
            x=pm(2,n);
            x=pm(x,mod-2)%mod;
            ans=(ans*x+mod)%mod;
            cout<<ans<<endl;
         }
        return 0; 
     }
    View Code

    J-Mind control(组合数化简)

    题意:

    如果给编号为x的人一个蛋糕,那么编号大于x的人都会崇拜你,现在分发m个蛋糕,求对你产生崇拜人数的期望

    思路:

    每次分发蛋糕,产生崇拜人数只会与x的最小值有关,剩下的m-1个蛋糕可以在编号为(x,n]的人中随意分发,那么就可以推出期望的表达式为

    但是这个公式的计算复杂度为O(n),1e6组询问下必TLE,所以还需对公式进行代换。

     

    后面的和式为一个组合恒等式,根据C(m,m)=C(m+1,m+1)以及C(m+1,m)+C(m+1,m+1)=C(m+2,m+1)可得证明:

    所以几个式子合并有:

    #include<iostream>
    #include<algorithm>
     using namespace std;
     typedef long long ll;
     const int mod=1e9+7;
     ll pow(ll a,ll b)
     {
         ll ans=1;
         while(b){
             if(b&1) ans=(a*ans)%mod;
             a=(a*a)%mod;
             b>>=1;
         }
        return ans;
     }
     int main()
     {
        ll n,m,t,ans;
        scanf("%lld",&t);
        while(t--){
            scanf("%lld%lld",&n,&m);
            if(m>n){
                cout<<n<<endl;
                continue;
            }
            ans=(n+1)*m%mod;
            ll x=pow(m+1,mod-2)%mod;
            ans*=x;
            ans=(ans+mod)%mod;
            printf("%lld
    ",ans);
        }
        return 0;
      } 
    View Code
  • 相关阅读:
    [JSOI2004]平衡点
    [HNOI2009]梦幻布丁
    蒜头君救人
    蒜头君的排序
    蒜头君的坐骑
    [ZJOI2006]超级麻将
    环状最大两段子段和
    洛谷P2480 [SDOI2010]古代猪文(卢卡斯定理+中国剩余定理)
    线性基学习笔记
    洛谷P2473 [SCOI2008]奖励关(期望+状压)
  • 原文地址:https://www.cnblogs.com/overrate-wsj/p/12499890.html
Copyright © 2011-2022 走看看