A 字符串构造机
怎么是原啊。。原我还没找。
然后考完找打发现上次场切了,这次没有。。。
就是并查集连边,考虑限制条件有两种,一定相等和一定不相等。维护一下。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n,m;
const int N=1e3+3;
struct op{int x,y,z;
}a[N];
int f[N];
int find(int x)
{if(x!=f[x]) return f[x]=find(f[x]);return x;
}
int num[N],ans[N];
inline bool cmp(op x,op y)
{if(x.x==y.x) return x.y<y.y;return x.x<y.x;
}
struct node{int a,b;
}anti[N];
int cnt;
int dis[N][N],cnt1[N];
bool ck[N][N];
signed main()
{freopen("str.in","r",stdin);freopen("str.out","w",stdout);cin>>n>>m;for(int i=1;i<=n;i++) f[i]=i,ans[i]=-1;for(int i=1;i<=m;i++){int x,y,z;cin>>x>>y>>z;if(y<x) swap(x,y);for(int j=0;j<z;j++) f[find(y+j)]=f[find(x+j)];if(y+z<=n)anti[++cnt].a=x+z,anti[cnt].b=y+z;}for(int i=1;i<=cnt;i++){int u=find(anti[i].a),v=find(anti[i].b);if(u==v) return cout<<"-1",0;if(!ck[u][v]) dis[u][++cnt1[u]]=v,dis[v][++cnt1[v]]=u;ck[u][v]=1;}for(int i=1;i<=n;i++){int pre=find(i);if(ans[pre]!=-1){ans[i]=ans[pre];}else{int now=0;unordered_map<int,bool>mp{};for(int j=1;j<=cnt1[pre];j++) mp[ans[dis[pre][j]]]=1;while(mp[now])++now;ans[i]=ans[pre]=now;}}for(int i=1;i<=n;i++) cout<<ans[i]<<" ";return 0;
}
B 忍者小队
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=6e5+10,M=3e5;
int n,m,cnt[N],mn[N],mx[N],g[N];
int p[N],tot,vis[N],mu[N];
signed main()
{freopen("sor.in","r",stdin);freopen("sor.out","w",stdout);ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);mu[1]=1;for(int i=2;i<=M;i++){if(!vis[i]) p[++tot]=i,mu[i]=-1;for(int j=1;j<=tot&&p[j]*i<=M;j++){vis[p[j]*i]=1;if(i%p[j]==0) break;mu[i*p[j]]=-mu[i];}}cin>>n>>m;for(int i=1,x;i<=n;i++) cin>>x,cnt[x]++;memset(mn,0x3f,sizeof(mn));for(int i=1;i<=M;i++) for(int j=i;j<=M;j+=i) mx[i]+=cnt[j];for(int i=M;i;i--){if(cnt[i]){mn[i]=1;continue;}for(int j=1;i*j<=M;j++) g[j]=0;for(int j=1;i*j<=M;j++)for(int k=j;i*k<=M;k+=j)g[k]+=mx[i*j]*mu[j];for(int j=2;i*j<=M;j++)if(g[j]) mn[i]=min(mn[i],mn[i*j]+1);}for(int i=1;i<=m;i++)if(mn[i]>1e9) cout<<"-1 -1\n";else cout<<mn[i]<<" "<<mx[i]<<"\n";return 0;
}
C 狗卡
考虑怎么最小。
结论是当选到第 \(i\) 个的某个连续序列,当且仅当这一段的平均数最小,每次扔到优先队列里头搞就行。
然后第一个包用按 \(a\) 排序的优先队列。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=6e5+5;
int n,m;
int k[N],*a[N];
inline int read()
{register int s=0;register char c=getchar();while(c<'0'||c>'9') c=getchar();while(c>='0'&&c<='9') s=(s<<1)+(s<<3)+(c^48),c=getchar();return s;
}
int cnt[N];
struct node{double so;int i,l,r;bool operator<(const node&ll) const{return so>ll.so;}
};
priority_queue<node>q;
signed main()
{freopen("dog.in","r",stdin);freopen("dog.out","w",stdout);n=read(),m=read();bool _=1;for(int i=1;i<=n;i++){k[i]=read();a[i]=new int [k[i]+2];int pos=0,sum=0;double mi=1e9;for(int j=1;j<=k[i];j++) {a[i][j]=read();if(j>1) _&=(a[i][j]>=a[i][j-1]);sum+=a[i][j];if(sum<mi*j) mi=1.0*sum/j,pos=j;}q.push({mi,i,1,pos});}if(_){priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > >q{};for(int i=1;i<=n;i++) q.push({a[i][1],i});int tim=0,now=0;int ans=0;while(!q.empty()){int pos=q.top().second;int val=q.top().first;q.pop();ans+=now*(val-1),tim+=val; now++;ans+=now;if(cnt[pos]<k[pos]-1) q.push({a[pos][cnt[pos]+2],pos});cnt[pos]++;}ans=ans+(m-tim-1)*now;return cout<<ans,0;}int tim=0,v=0;int ans=0;while(!q.empty()){node now=q.top();
// cout<<pos<<" "<<val<<"\n";q.pop();for(int i=now.l;i<=now.r;i++){ans+=v*a[now.i][i];tim+=a[now.i][i];++v;}int pos=0,sum=0;double mi=1e9;for(int j=now.r+1;j<=k[now.i];j++) {sum+=a[now.i][j];if(sum<mi*(j-now.r)) mi=1.0*sum/(j-now.r),pos=j;}if(now.r+1<=k[now.i])q.push({mi,now.i,now.r+1,pos});}ans=ans+(m-tim)*v;cout<<ans;
}