noip模拟14
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;
}