2017.8.27 考试

考场做法:

把所有的边按编号小的点从大到小排序

依次加边,并查集维护

合并时 fa[]强制为编号小的点

当出现环时,如果fa<=k,ans++

#include<cstdio>
#include<iostream>
#include<algorithm>
#define N 1000001
#define M 2000001
using namespace std;
int fa[N];
struct node
{
    int u,v;
}e[M];
void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
}
int find(int i) { return fa[i]==i ? fa[i] : fa[i]=find(fa[i]); }
bool cmp(node p,node q)
{
    if(p.u!=q.u) return p.u>q.u;
    return p.v>q.v;
}
int main()
{
    freopen("tour.in","r",stdin);
    freopen("tour.out","w",stdout);
    int n,m,k;
    read(n); read(m); read(k);
    for(int i=1;i<=n;i++) fa[i]=i;
    int u,v,r1,r2,tmp1=0,tmp2=0,tot=0;
    for(int i=1;i<=m;i++) 
    {
        read(u); read(v);
        if(u==v) { tmp1++; continue; }
        e[++tot].u=min(u,v);
        e[tot].v=max(u,v);
    }
    m=tot;
    sort(e+1,e+m+1,cmp);
    for(int i=1;i<=m;i++)
    {
        u=e[i].u; v=e[i].v;
        r1=find(u); r2=find(v);
        if(r1!=r2) 
        {
            if(r1<r2) swap(r1,r2);
            fa[r1]=r2;
        }
        else if(fa[r1]<=k) tmp2++;
    }
    printf("%d",tmp1+tmp2);
}
View Code

上面解法中的排序没有必要

将边分为两类

1、定点编号都>k

2、至少有一个点的编号<=k

先把第一类用并查集合并

合并第二类时,遇环就ans++

#include<cstdio>
#include<iostream>
#define N 1000001
#define M 2000001
using namespace std;
int fa[N];
struct node
{
    int u,v;
}e[M];
int find(int i) { return fa[i]==i ? i : fa[i]=find(fa[i]); }
int read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
}
int main()
{
    freopen("tour.in","r",stdin);
    freopen("tour.out","w",stdout);
    int n,m,k;
    read(n); read(m); read(k);
    for(int i=1;i<=n;i++) fa[i]=i;
    int u,v,r1,r2,tot=0;
    for(int i=1;i<=m;i++)
    {
        read(u); read(v);
        if(u>k && v>k)
        {
            r1=find(u);  r2=find(v);
            fa[r1]=r2;
        }
        else
        {
            e[++tot].u=u; e[tot].v=v;
        }
    }
    int ans=0;
    for(int i=1;i<=tot;i++)
    {
        r1=find(e[i].u); r2=find(e[i].v);
        if(r1==r2) ans++;
        fa[r1]=r2;
    }
    printf("%d",ans);
}
View Code

每个数最多开6次就变成1了

线段树维护区间是否全变成1

全变成1了就跳过

注意l可能大于r,被坑了

#include<cmath>
#include<cstdio>
#include<iostream>
#define N 100001
using namespace std;
typedef long long LL;
LL sum[N<<2],ans;
int mid[N<<2];
bool f[N<<2];
int opl,opr;
void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
}
void read(LL &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
}
void build(int k,int l,int r)
{
    if(l==r) 
    { 
        read(sum[k]); 
        if(sum[k]==1) f[k]=true;
        return;
    }
    mid[k]=l+r>>1;
    build(k<<1,l,mid[k]);
    build(k<<1|1,mid[k]+1,r);
    sum[k]=sum[k<<1]+sum[k<<1|1];
    f[k]=f[k<<1]&f[k<<1|1];
}
void change(int k,int l,int r)
{
    if(f[k]) return;
    if(l==r) 
    {
        sum[k]=sqrt(sum[k]);
        if(sum[k]==1) f[k]=true;
        return;
    }
    if(opl<=mid[k]) change(k<<1,l,mid[k]);
    if(opr>mid[k]) change(k<<1|1,mid[k]+1,r);
    sum[k]=sum[k<<1]+sum[k<<1|1];
    f[k]=f[k<<1]&f[k<<1|1];
}
void query(int k,int l,int r)
{
    if(l>=opl && r<=opr) { ans+=sum[k]; return; }
    if(opl<=mid[k]) query(k<<1,l,mid[k]);
    if(opr>mid[k]) query(k<<1|1,mid[k]+1,r);
}
void out(LL x)
{
    if(x/10) out(x/10);
    putchar(x%10+'0');
}
int main()
{
    freopen("sequence.in","r",stdin);
    freopen("sequence.out","w",stdout);
    int n,m,ty; 
    read(n);
    build(1,1,n);
    read(m);
    while(m--)
    {
        read(ty); read(opl); read(opr);
        if(opl>opr) swap(opl,opr);
        if(!ty)  change(1,1,n);
        else ans=0,query(1,1,n),out(ans),printf("
");
    }
}
View Code

 

单词i向单词j连一条边,边权为j接到i后面所需的增加的长度

0向每个单词连边权为单词长度的边

那么题意转化为在这张图上走m步的最短长度

 单词只有200,出现次数很大

用倍增加速floyd

#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#define N 201
#define M 100001
using namespace std;
typedef unsigned long long LL;
const int seed=131;
int n,m;
string s[N];
vector<LL>hash[N];
LL bit[M],h[M]; 
struct mat
{
    LL a[N][N];
    void init()
    {
        memset(a,-1,sizeof(a));
    }
    mat operator * (mat b)
    {
        mat res; 
        res.init();
        for(int k=0;k<=n;k++)
            for(int i=0;i<=n;i++)
                if(a[i][k]!=-1)
                    for(int j=0;j<=n;j++)
                        if(b.a[k][j]!=-1)
                            res.a[i][j]=res.a[i][j]<0 ? a[i][k]+b.a[k][j] : min(res.a[i][j],a[i][k]+b.a[k][j]);
        return res;
    }
};
void out(LL x)
{
    if(x/10) out(x/10);
    putchar(x%10+'0');
}
void solve()
{
    mat x; 
    x.init();
    for(int i=1;i<=n;i++) x.a[0][i]=s[i].length();
    for(int i=1;i<=n;i++)
    {
        int t1=s[i].length(),mx=0;
        LL cur=0;
        for(t1--;t1>=0;--t1)
        {
            cur+=s[i][t1]*bit[mx];
            h[mx++]=cur;
        }
        for(int j=1;j<=n;j++)
        {
            int len=min(s[i].length(),s[j].length()),res=0;
            if(i==j) --len;
            for(int k=0;k<len;k++)
                if(h[k]==hash[j][k]) res=k+1;
            x.a[i][j]=s[j].length()-res;
        }
    }
    mat res; res=x;
    for(--m;m;m>>=1,x=x*x)
        if(m&1) res=res*x;
    LL ans=1e18;
    for(int i=1;i<=n;i++) ans=min(ans,res.a[0][i]);
    out(ans);
}
int main()
{
    freopen("hamster.in","r",stdin);
    freopen("hamster.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        cin>>s[i];
        LL cur=0;
        int len=s[i].length();
        for(int j=0;j<len;j++)
        {
            cur=cur*seed+s[i][j];
            hash[i].push_back(cur);
        }
    }
    bit[0]=1;
    for(int i=1;i<M;i++) bit[i]=bit[i-1]*seed;
    solve();
}
View Code

考场kmp预处理+dfs10分代码:

#include<ctime>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
char s[201][100001];
char ss[200001];
int tim,n,m,minn=1e5+1,cut[201][201],len[201],f[201],ans;
int kmp(int a,int l)
{
    int j;
    for(int i=1;i<l;i++)
    {
        j=f[i];
        while(j && ss[i]!=ss[j]) j=f[j];
        f[i+1]= ss[i]==ss[j] ? j+1 : 0;        
    }
    int now=f[l];
    while(now>=a) now=f[now];
    return now;
}
void dfs(int now,int last,int length,bool have)
{
    if(clock()-tim>=2980)
    {
        printf("%d",ans);
        exit(0);
    }
    if(length>=ans) return;
    if(now==m+1) 
    {
        ans=length;
        return;
    }
    for(int i=1;i<=n;i++)
        if(!last || cut[i][last] || have)  
            dfs(now+1,i,length+len[i]-cut[i][last],cut[i][last]);
}
int main()
{
    freopen("hamster.in","r",stdin);
    freopen("hamster.out","w",stdout);
    tim=clock();
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",s[i]);
        len[i]=strlen(s[i]);
        minn=min(minn,len[i]);
    }
    int l;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        {
            l=0;
            for(int k=0;k<len[i];k++) ss[l++]=s[i][k];
            for(int k=0;k<len[j];k++) ss[l++]=s[j][k];
            cut[i][j]=kmp(len[i],l);
        }    
    ans=minn*m;
    dfs(1,0,0,false);
    printf("%d",ans);
}
View Code
原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/7461891.html