计蒜之道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)