码迷,mamicode.com
首页 > 其他好文 > 详细

EXAM-2018-08-21

时间:2018-08-26 23:46:04      阅读:342      评论:0      收藏:0      [点我收藏+]

标签:struct   code   find   end   简单   print   矛盾   区域   多少   

EXAM-2018-08-21

自己真的是菜的恐怖

D:Fence Building

欧拉公式:V-E+F=2
在平面中:V为顶点个数,E为边数,F为区域数
在简单几何体中:V为顶点个数,E为边数,F为面数

考虑到区域最多,每个交点最多由两条线构成。 顶点数为C(n,4);边数为C(n,2)+2*C(n,4) 然后减去圆外的.

I: A Possible Tree

  • 题意: 给定一棵带权树的形态, 但是并不知道每天条边的具体权重. 然后给m个信息, 信息格式为u v val, 表示在树上u 到 v 的路径上经过的边的权重的异或和为val, 问前面最多有多少个信息是不冲突的.
  • 题解:从冲不冲突应该想到使用并查集,通过那m次信息构建最小生成树,如果不属于这个集合的就加入集合,属于的就判断是否与之前的最小生成树矛盾。主要是在这个集合内的两点,可以很轻松查询到。(画图理解)val[]记录根节点到该点的距离,然后通过find时路径压缩的操作和add操作更新val[]。这道题写起来很简单,就是难想到。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+7;
int fa[maxn],val[maxn];
int n;
template<class T>
void read(T &res){
    res=0;
    T f=1;
    char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-') f=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9'){
        res=res*10+c-'0';
        c=getchar();
    }
    res*=f;
}
void init()
{
    for(int i=0;i<=n;i++) fa[i]=i;
    memset(val,0,sizeof(val));
}
int findd(int u){
    if(u!=fa[u]){
     int v=fa[u];
     fa[u]=findd(v);
     val[u]^=val[v];
    }
    return fa[u];
}
bool add(int u,int v,int w){
    int a=findd(u);
    int b=findd(v);
    if(a!=b){
        val[a]=val[v]^val[u]^w;
        fa[a]=b;
        return true;
    }
    if((val[u]^val[v])!=w) return false;
    else return true;
}
int main(){
    int t;
    read(t);
    int u,v,m,w;
    while(t--){
        read(n);
        read(m);
        init();
        for(int i=1;i<n;i++){
            read(u);
            read(v);
        }
        int flag=0;
        for(int i=1;i<=m;i++){
            read(u);
            read(v);
            read(w);
            if(!add(u,v,w)&&!flag){
                flag=i;
            }
        }
        printf("%d\n",flag-1);
    }
    return 0;
}

H Count Numbers

cur[n]表示数位和为n的方案数,ans[n]表示前n位的答案。 我们发现,比如说4,方案数等于cur[2]+cur[2],cur[3]+cur[1],cur[4]+cur[0]。通过枚举最后一位就可以得到答案。

cur[i]=SUM cur[i-j];

而和就是前面的位* 10加上与i的差*与i的差的数的方案数。

ans[i]=SUM ans[i-j]*10+j*cur[i-j];

接下来就是矩阵快速幂 枚举18位 构成18*18的矩阵
然后注意写法就好。__int128

#include <bits/stdc++.h>
#define ll long long
using namespace std;
template<class T>
void read(T &res){
    res=0;
    T f=1;
    char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-') f=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9'){
        res=res*10+c-'0';
        c=getchar();
    }
    res*=f;
}
struct mac{
    ll f[20][20];
    mac(){
       for(int i=0;i<20;i++){
        for(int j=0;j<20;j++){
            f[i][j]=0;
        }
       }
    }
    void init()
    {
        for(int i=0;i<20;i++){
             
                f[i][i]=1;
        }
    }
};
int p;
mac operator*(mac a,mac b)
{
    mac c;
    for(int i=0;i<18;i++){
        for(int j=0;j<18;j++){
            if(a.f[i][j])
            for(int k=0;k<18;k++){
                if(b.f[j][k]){
                c.f[i][k]=c.f[i][k]+(a.f[i][j]%p*b.f[j][k]%p)%p;
                if(c.f[i][k]>=p) c.f[i][k]-=p;
                }
            }
        }
    }
    return c;
}
mac qpow(mac a,__int128 k)
{
    mac c;
    c.init();
    while(k>0){
        if(k&1) c=c*a;
        a=a*a;
        k>>=1;
    }
    return c;
}
ll ans[18],cur[18];
int main()
{
    int t;int x,y;
    mac a,b;
    read(t);
    cur[0]=1;
    for(int i=1;i<=9;i++){
        for(int j=1;j<=i;j++){
            cur[i]+=cur[i-j];
            ans[i]+=10*ans[i-j]+j*cur[i-j];
        }
    }
    for(int i=0;i<9;i++) a.f[i][0]=10;
    for(int i=9;i<18;i++) a.f[i][0]=i-8;
    for(int i=1;i<9;i++){
        a.f[i-1][i]=1;
    }
    for(int i=10;i<18;i++){
        a.f[i-1][i]=1;
    }
    for(int i=9;i<18;i++){
        a.f[i][9]=1;
    }
//    for(int i=0;i<18;i++){
//        for(int j=0;j<18;j++){
//            cout<<setw(3)<<a.f[i][j];
//        }
//        cout<<endl;
//    }
    while(t--){
        read(x);
        read(y);
        read(p);
        for(int i=0;i<9;i++) b.f[0][i]=ans[9-i]%p;
        for(int j=9;j<18;j++) b.f[0][j]=cur[18-j]%p;
//        for(int i=0;i<18;i++){
//            cout<<b.f[0][i]<<" ";
//        }
        __int128 k=1;
        for(int i=1;i<=y;i++) k*=(__int128)x;
        //cout<<k<<endl;
        if(k<=9){
            printf("%lld\n",ans[k]%p);
        }
        else{
            mac ak=b*qpow(a,k-9);
            printf("%lld\n",ak.f[0][0]);
        }
    }
    return 0;
}
/*5
3 2 100000
*/

EXAM-2018-08-21

标签:struct   code   find   end   简单   print   矛盾   区域   多少   

原文地址:https://www.cnblogs.com/smallocean/p/9539450.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!