计蒜之道2018复赛

待续。。。

 

A题

考虑任意两个一次函数,哪个放在里面更有

y=ax+b和y=cx+d;

sort时满足(ax+b)x+d>(cx+d)x+b即可,在O(n)计算即可

D题

 

#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#define maxn 100002
using namespace std;
int inf[2],s[2][maxn],fa[maxn],now,ans;
vector<int>e[maxn];
char is[20];
bool vis[maxn],ind[maxn],ct[maxn],ex[maxn];
inline int find(int x) {return fa[x]==x?x: fa[x]=find(fa[x]);}
inline void unionn(int u,int v){
      int x=find(u),y=find(v);
      if(x!=y)fa[x]=y;
      return ;
}
inline bool dfs(int u){
      ind[u]=1;
      vis[u]=1;
      int flag=0,siz=e[u].size();
      for(int p=0;p<siz;p++){
          if(ind[e[u][p]]){flag=1;continue;}
          if(vis[e[u][p]])continue;
          if(dfs(e[u][p])) flag=1;
      }
      ind[u]=0;
      return flag;
  }
int main(){
    int n;scanf("%d",&n);
    for(int i=0;i<2;i++){
        scanf("%s",is);
        if(strcmp(is,"Constant")==0)inf[i]=0;else inf[i]=1;
        for(int j=1;j<=n;j++)scanf("%d",&s[i][j]);
    }
    if(inf[0]==0)now=1;else now=0;
    int pt=inf[0]+inf[1];
    for(int i=1;i<=100000;i++)fa[i]=i;
    for(int i=1;i<=n;i++){
        if(pt>=1 && s[now][i]!=s[now^1][i])e[s[now][i]].push_back(s[now^1][i]),unionn(s[now][i],s[now^1][i]);
        ex[s[now][i]]=1;ex[s[now^1][i]]=1;
    }
    ans=0;
    for(int i=1;i<=100000;i++){
        if(e[i].size()>0){
            sort(e[i].begin(),e[i].end());
            e[i].resize(unique(e[i].begin(),e[i].end())-e[i].begin());
        }
        if(ex[i])ans++;
    }
    if(pt==0){
        bool flag=0;
        for(int i=1;i<=n;i++)if(s[0][i]!=s[1][i])flag=1;
        if(flag)printf("-1\n");else printf("0\n");
    }
    if(pt==1){
        for(int i=1;i<=100000;i++)if(ex[i] && !vis[i])if(dfs(i))ct[find(i)]=1;
        for(int i=1;i<=100000;i++)if(ex[i] && fa[i]==i && ct[i]==0)ans--;
        printf("%d\n",ans);
    }
    if(pt==2){
        for(int i=1;i<=100000;i++)if(ex[i] && fa[i]==i)ans--;
        printf("%d\n",ans);
    }
    return 0;
}

 

E题

发现这题好简单,考场上看到通过的人那么少就不敢打了 m^-w-^m

将一个点拆成两个点,维护最大值和最小值,因为a会小于0

若一个值被更新了2*n次,那么就肯定能达到无穷大或无穷小

#include<cstdio>
#include<cctype>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const long long inf=2e14;
const int maxn=5002;
const int maxm=10002;
int n,m,cnt,flag,head[maxn],tot[maxm];
bool vis[maxn];
queue<int>q;
struct node{long long maxn,minn;}a[maxn];
struct data{int v,nex,a,b;}edge[maxm];
inline int read(){
    char ch=getchar();int x=0,f=1;
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*=f;
}
inline void addedge(int u,int v,int a,int b){edge[++cnt].v=v;edge[cnt].a=a;edge[cnt].b=b;edge[cnt].nex=head[u];head[u]=cnt;}
inline void spfa(){
    long long tmp1,tmp2,tmp;int x,v;
    while(!q.empty())q.pop();
    q.push(1);vis[1]=1;tot[1]++;tot[1+n]++;
    while(!q.empty()){
        x=q.front();q.pop();vis[x]=0;
        for(int i=head[x];i;i=edge[i].nex){
            v=edge[i].v;
            if(a[x].maxn==inf){if(edge[i].a>0)tmp1=inf;if(edge[i].a==0)tmp1=1LL*edge[i].b;if(edge[i].a<0)tmp1=-inf;}
            else tmp1=1LL*edge[i].a*a[x].maxn+1LL*edge[i].b;
            if(a[x].minn==-inf){if(edge[i].a>0)tmp2=-inf;if(edge[i].a==0)tmp2=1LL*edge[i].b;if(edge[i].a<0)tmp2=inf;}
            else tmp2=1LL*edge[i].a*a[x].minn+1LL*edge[i].b;
            if(tmp1>tmp2){tmp=tmp1;tmp1=tmp2;tmp2=tmp;}
            if(tmp1<a[v].minn){
                a[v].minn=tmp1;tot[v]++;if(tot[v]>2*n)a[v].minn=-inf;
                if(!vis[v]){vis[v]=1;q.push(v);}
            }
            if(tmp2>a[v].maxn){
                a[v].maxn=tmp2;tot[v+n]++;if(tot[v+n]>2*n)a[v].maxn=inf;
                if(!vis[v]){vis[v]=1;q.push(v);}
            }
            if(v==n)flag=1;
        }
    }
}
int main(){
    int T,x0,x1,x2,x3;T=read();
    while(T--){
        n=read();m=read();cnt=flag=0;
        a[1].maxn=a[1].minn=0;for(int i=2;i<=n;i++){a[i].maxn=-inf;a[i].minn=inf;}
        for(int i=1;i<=m;i++){x0=read();x1=read();x2=read();x3=read();addedge(x0,x1,x2,x3);}
        spfa();
        if(!flag)printf("No solution\n");else if(a[n].maxn==inf)printf("Infinity\n");else printf("%lld\n",a[n].maxn);
        for(int i=1;i<=n;i++)head[i]=0,vis[i]=0;
        for(int i=1;i<=2*n;i++)tot[i]=0;
    }
    return 0;
}

 

G题

逆元处理下

1、统计‘a'~'z'各自出现次数(cnt数组记录)

2.遍历一遍t串,将其中出现的字母先固定t串,cnt[ t[ i ] ]--;

3, ans=(lens-lent+1)*!(lens-lent)/(!cnt[1~26)

 

posted @ 2018-06-19 18:54  lnyzo  阅读(242)  评论(0编辑  收藏  举报