• AIM Tech Round 4 Div. 1


      A:显然最优方案是对所形成的置换的每个循环排个序。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    using namespace std;
    #define ll long long
    #define N 100010
    char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
    int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
    int read()
    {
    	int x=0,f=1;char c=getchar();
    	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    	return x*f;
    }
    int n,a[N],c[N];
    vector<int>  b;
    bool flag[N];
    signed main()
    {
    #ifndef ONLINE_JUDGE
    	freopen("a.in","r",stdin);
    	freopen("a.out","w",stdout);
    #endif
    	n=read();
    	for (int i=1;i<=n;i++) c[i]=a[i]=read();
    	sort(c+1,c+n+1);
    	for (int i=1;i<=n;i++) a[i]=lower_bound(c+1,c+n+1,a[i])-c;
    	int ans=0; 
    	for (int i=1;i<=n;i++)
    	if (!flag[i])
    	{
    		flag[i]=1;int x=i;
    		while (!flag[a[x]]) x=a[x],flag[x]=1;
    		ans++;
    	}
    	cout<<ans<<endl;
    	memset(flag,0,sizeof(flag));
    	for (int i=1;i<=n;i++)
    	if (!flag[i])
    	{
    		b.clear();
    		int cnt=1;flag[i]=1;int x=i;b.push_back(i);
    		while (!flag[a[x]]) x=a[x],flag[x]=1,cnt++,b.push_back(x);
    		printf("%d ",cnt);
    		for (int j=0;j<cnt;j++) printf("%d ",b[j]);printf("
    ");
    	}
    	return 0;
    	//NOTICE LONG LONG!!!!!
    }
    

      B:随机问1000个位置,然后找到x在其中哪个区间内暴力询问即可。注意最好不要rand。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<ctime>
    #include<vector>
    #include<chrono>
    #include<random>
    using namespace std;
    #define ll long long
    #define N 50010
    char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
    int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
    int read()
    {
    	int x=0,f=1;char c=getchar();
    	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    	return x*f;
    }
    int n,start,x,val[N],nxt[N];
    bool flag[N];
    struct data{int p,val,nxt;
        bool operator <(const data&a) const
        {
            return val<a.val;
        }
    }a[N];
    signed main()
    {
    #ifndef ONLINE_JUDGE
    	freopen("a.in","r",stdin);
    	freopen("a.out","w",stdout);
    #endif
    	n=read(),start=read(),x=read();
    	mt19937 rnd(time(0));
    	cout<<"?"<<' '<<start<<endl;
    	flag[start]=1;cin>>val[start]>>nxt[start];
    	if (val[start]>=x) {cout<<"!"<<' '<<val[start]<<endl;return 0;}
    	for (int i=1;i<=999;i++)
    	{
    		int x=rnd()%n+1;
    		cout<<"?"<<' '<<x<<endl;
    		flag[x]=1;cin>>val[x]>>nxt[x];
    	}
    	int t=0;
    	for (int i=1;i<=n;i++) if (flag[i]) a[++t].p=i,a[t].nxt=nxt[i],a[t].val=val[i];
    	sort(a+1,a+t+1);
    	a[t+1].val=1010000000;
    	for (int i=1;i<=t;i++)
    	if (a[i].val<=x&&a[i+1].val>x)
    	{
    	    int u=a[i].nxt,v=a[i].val;
    	    if (v>=x) {cout<<"!"<<' '<<v<<endl;return 0;}
    	    while (u!=-1&&v<x)
    	    {
    	        cout<<"?"<<' '<<u<<endl;
    	        cin>>v>>u;
    	    }
    	    if (v>=x)
    	    {
    	        cout<<"!"<<' '<<v<<endl;return 0;
    	    }
    	    else {cout<<"!"<<' '<<-1<<endl;return 0;}
    	}
    	return 0;
    	//NOTICE LONG LONG!!!!!
    }
    

      C:容易发现重心的各棵子树的点集是不能改变的。然后一堆人比如我就扔个点分上去肯定就假了。事实上可以通过这种操作将任意一棵子树展开成链,链可以再转化成菊花,分别消耗低于n次。第一步逐个考虑当前点的每个子树(都已经形成链),将当前点与父亲切断,并将该子树所形成的链的底端接到父亲。第二步由链底端自下往上切掉,并将原本的菊花中心接上即可。注意判一下有两个重心的情况。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<set>
    #include<cassert>
    using namespace std;
    #define ll long long
    #define N 400010
    char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
    int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
    int read()
    {
    	int x=0,f=1;char c=getchar();
    	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    	return x*f;
    }
    int n,p[N],size[N],ansx[N],ansy[N],ansz[N],fa[N],top[N],pre[N],u,root,root2,t;
    set<int> e[N];
    struct data{int to,nxt;
    }edge[N<<1];
    void addedge(int x,int y){t++;e[x].insert(y);edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
    void make(int k,int from)
    {
        size[k]=1;
        for (int i=p[k];i;i=edge[i].nxt)
        if (edge[i].to!=from)
        {
            make(edge[i].to,k);
            size[k]+=size[edge[i].to];
        }
    }
    int findroot(int k,int s,int from)
    {
        int mx=0;
        for (int i=p[k];i;i=edge[i].nxt)
        if (edge[i].to!=from&&size[edge[i].to]>size[mx]) mx=edge[i].to;
        if ((size[mx]<<1)>s) return findroot(mx,s,k);
        else return k;
    }
    void solve(int k,int from)
    {
    	fa[k]=from;
    	for (int i=p[k];i;i=edge[i].nxt)
    	if (edge[i].to!=from&&edge[i].to!=root&&edge[i].to!=root2) solve(edge[i].to,k);
    	for (int i=p[k];i;i=edge[i].nxt)
    	if (edge[i].to!=from&&edge[i].to!=root&&edge[i].to!=root2)
    	{
    		if (!top[k]) top[k]=edge[i].to;
    		ansx[++u]=fa[k];
    		ansy[u]=k;
    		ansz[u]=edge[i].to;
    		e[ansx[u]].erase(ansy[u]),e[ansx[u]].insert(ansz[u]);
    		e[ansy[u]].erase(ansx[u]),e[ansz[u]].insert(ansx[u]);
    		fa[k]=top[edge[i].to];
    	}
    	if (!top[k]) top[k]=k;
    }//����kΪ�����������һ���� 
    int get(int x)
    {
    	while (1)
    	{
    		auto it=e[x].begin();
    		while (it!=e[x].end()&&(*it)==pre[x]) it++;
    		if (it==e[x].end()) return x;
    		else pre[*it]=x,x=*it;
    	}
    }
    signed main()
    {
    #ifndef ONLINE_JUDGE
    	freopen("a.in","r",stdin);
    	freopen("a.out","w",stdout);
    #endif
    	n=read();
    	for (int i=1;i<n;i++)
    	{
    		int x=read(),y=read();
    		addedge(x,y),addedge(y,x);
    	}
    	make(1,1);
    	root=findroot(1,n,1);
    	if (n%2==0)
    	{
    		for (int i=1;i<=n;i++)
    		if (size[i]==n/2) {root2=i;break;}
    	}
    	if (root2)
    	{
    		for (int i=p[root2];i;i=edge[i].nxt)
    		if (edge[i].to!=root)
    		{
    			solve(edge[i].to,root2);
    			pre[top[edge[i].to]]=root2;
    			int x=get(top[edge[i].to]),k=x;
    			while (k!=root2)
    			{
    				ansx[++u]=pre[k];
    				ansy[u]=k;
    				ansz[u]=x;
    				k=pre[k];
    			}
    		}
    	}
    	for (int i=p[root];i;i=edge[i].nxt)
    	if (edge[i].to!=root2)
    	{
    		solve(edge[i].to,root);
    		pre[top[edge[i].to]]=root;
    		int x=get(top[edge[i].to]),k=x;
    		while (k!=root)
    		{
    			ansx[++u]=pre[k];
    			ansy[u]=k;
    			ansz[u]=x;
    			k=pre[k];
    		}
    	}
    	printf("%d
    ",u);
    	for (int i=1;i<=u;i++)  printf("%d %d %d
    ",ansx[i],ansy[i],ansz[i]);
    	return 0;
    	//NOTICE LONG LONG!!!!!
    }
    

      D:注意到dij的堆如果可以用桶替代就能做到线性最短路,这要求值域较小,而题面保证了总边权变化量不超过1e6。考虑怎么仅对变化量做最短路。一开始跑完dij后,将每条边(u,v)的边权重赋值为disu+w(u,v)-disv建成新图,每次修改就在新图中进行修改并跑桶优化dij,再将得到的最短路值累加,并继续对新图进行重赋值即可。好像每次边权只+1并没有什么卵用?

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<vector>
    using namespace std;
    #define ll long long
    #define N 100010
    #define inf 10000000000000000ll
    char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
    int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
    int read()
    {
    	int x=0,f=1;char c=getchar();
    	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    	return x*f;
    }
    int n,m,Q,p[N],t;
    ll d[N],d2[N];
    bool flag[N];
    vector<int> a[N];
    struct data{int to,nxt;ll len;
    }edge[N];
    void addedge(int x,int y,int z){t++;edge[t].to=y,edge[t].nxt=p[x],edge[t].len=z,p[x]=t;}
    struct data2
    {
    	int x;ll d;
    	bool operator <( const data2&a) const
    	{
    		return d>a.d;
    	}
    };
    priority_queue<data2> q;
    void dijkstra()
    {
    	memset(d,42,sizeof(d));d[1]=0;
    	q.push((data2){1,0});
    	for (;;)
    	{
    		while (!q.empty()&&flag[q.top().x]) q.pop();
    		if (q.empty()) break;
    		data2 x=q.top();q.pop();
    		flag[x.x]=1;
    		for (int i=p[x.x];i;i=edge[i].nxt)
    		if (x.d+edge[i].len<d[edge[i].to])
    		{
    			d[edge[i].to]=x.d+edge[i].len;
    			q.push((data2){edge[i].to,d[edge[i].to]});
    		}
    	}
    	for (int i=1;i<=n;i++)
    		for (int j=p[i];j;j=edge[j].nxt)
    		edge[j].len=d[i]+edge[j].len-d[edge[j].to];
    }
    void update(int c)
    {
    	memset(d2,42,sizeof(d2));
    	memset(flag,0,sizeof(flag));
    	for (int i=0;i<=c;i++) a[i].clear();
    	a[0].push_back(1);d2[1]=0;
    	for (int i=0;i<=c;i++)
    	{
    		for (int k=0;k<a[i].size();k++)
    		{
    			int x=a[i][k];
    			if (!flag[x])
    			{
    				flag[x]=1;
    				for (int j=p[x];j;j=edge[j].nxt)
    				if (d2[x]+edge[j].len<d2[edge[j].to]&&d2[x]+edge[j].len<=c)
    				{
    					d2[edge[j].to]=d2[x]+edge[j].len;
    					a[d2[edge[j].to]].push_back(edge[j].to);
    				}
    			}
    		}
    	}
    	for (int i=1;i<=n;i++)
    		for (int j=p[i];j;j=edge[j].nxt)
    		edge[j].len=d2[i]+edge[j].len-d2[edge[j].to];
    	for (int i=1;i<=n;i++) if (d2[i]<inf) d[i]+=d2[i];
    }
    signed main()
    {
    #ifndef ONLINE_JUDGE
    	freopen("a.in","r",stdin);
    	freopen("a.out","w",stdout);
    #endif
    	n=read(),m=read(),Q=read();
    	for (int i=1;i<=m;i++)
    	{
    		int x=read(),y=read(),z=read();
    		addedge(x,y,z);
    	}
    	dijkstra();
    	for (int i=1;i<=Q;i++)
    	{
    		int op=read();
    		if (op==1)
    		{
    			int x=read();
    			if (d[x]>inf) printf("-1
    ");
    			else printf("%I64d
    ",d[x]);
    		}
    		else
    		{
    			int c=read();
    			for (int j=1;j<=c;j++) edge[read()].len++;
    			update(c);
    		}
    	}
    	return 0;
    	//NOTICE LONG LONG!!!!!
    }
    

      

  • 相关阅读:
    【codeforces 755A】PolandBall and Hypothesis
    【codeforces 755B】PolandBall and Game
    【codeforces 755C】PolandBall and Forest
    Enhancing network controls in mandatory access control computing environments
    NPM 使用介绍
    【oracle】首次启动SQL Developer配置java.exe出错(Could not find jvm.cfg! )
    day70-oracle PLSQL_02光标
    day69-oracle 22-DBCA
    day70-oracle 12-Java调用存储过程和存储函数
    day17 16.关于sql注入与PreparedStatement介绍
  • 原文地址:https://www.cnblogs.com/Gloid/p/10527122.html
Copyright © 2020-2023  润新知