POI2018
阿新 • • 發佈:2018-11-19
Plan metra:
找出 - 的路徑後隨便構造就行了,一開始我想找 相等的點作為路徑上的點,其實找 最小的才是正確的,然後還要特判 和 直接相連的情況,這時可以用所有點 相同來判斷,但是當 都為 時, 和 不是直接相連的,要特判。
程式碼:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int Maxn=500010;
const int inf=2147483647;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
int n,mn=inf,lb=0,len=0;
struct Node{int d1,dn,x,id;}a[Maxn],b[Maxn];
bool cmp(Node a,Node b){return a.d1<b.d1;}
struct Edge{int x,y,d;}e[Maxn];
int mark[1000010];
int main()
{
n=read();bool flag=true;
if(n==2)return printf("TAK\n1 2 1"),0;
for(int i=2;i<n;i++)a[i].d1=read(),a[i].id=i;
for(int i=2;i<n;i++)
{
a[i].dn=read();
a[i].x=a[i].d1-a[i].dn;
mn=min(mn,a[i].d1+a[i].dn);
if(i>2&&abs(a[i].x)!=abs(a[i-1].x))flag=false;
}
if(flag)
{
int dis=abs(a[2].x);
if(!dis)
{
if(n==3)
{
puts("TAK");
printf("%d %d %d\n",1,2,a[2].d1);
printf("%d %d %d\n",3,2,a[2].d1);
return 0;
}
sort(a+2,a+n,cmp);
if(a[2].d1==a[3].d1)return puts("NIE"),0;
puts("TAK");
printf("%d %d %d\n",1,a[2].id,a[2].d1);
printf("%d %d %d\n",n,a[2].id,a[2].d1);
for(int i=3;i<n;i++)printf("%d %d %d\n",a[2].id,a[i].id,a[i].d1-a[2].d1);
return 0;
}
puts("TAK");
printf("%d %d %d\n",1,n,dis);
for(int i=2;i<n;i++)
{
if(a[i].x>0)printf("%d %d %d\n",i,n,a[i].d1-dis);
else printf("%d %d %d\n",i,1,a[i].dn-dis);
}
return 0;
}
else
{
memset(mark,-1,sizeof(mark));
int dis=mn;
for(int i=2;i<n;i++)
{
if(a[i].x==dis)e[++len].x=i,e[len].y=n,e[len].d=a[i].d1-dis;
else if(a[i].x==-dis)e[++len].x=i,e[len].y=1,e[len].d=a[i].dn-dis;
else b[++lb]=a[i],b[lb].id=i;
}
sort(b+1,b+1+lb,cmp);
int last=1,lastd=0;
for(int i=1;i<=lb;i++)
{
if(b[i].d1+b[i].dn==dis)
{
e[++len].x=last,e[len].y=b[i].id,e[len].d=b[i].d1-lastd;
if(e[len].d<=0)return puts("NIE"),0;
last=b[i].id,lastd=b[i].d1;mark[b[i].d1]=b[i].id;
}
else
{
int d=b[i].d1+b[i].dn-dis;
if(d&1)return puts("NIE"),0;
d>>=1;
if(b[i].d1<=d||mark[b[i].d1-d]==-1)return puts("NIE"),0;
e[++len].x=mark[b[i].d1-d],e[len].y=b[i].id,e[len].d=d;
}
}
e[++len].x=last,e[len].y=n,e[len].d=dis-lastd;
if(len!=n-1||e[len].d<=0)return puts("NIE"),0;
puts("TAK");
for(int i=1;i<=len;i++)printf("%d %d %d\n",e[i].x,e[i].y,e[i].d);
}
}
Powódź:
這個題的話抓住如果某個格子的水位高於牆,那麼它周圍的一些格子的水位必須跟它一樣這個性質做,按照牆的高度排序,每次把兩個塊合併,維護合法的答案、高度即可。
程式碼:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int Maxn=500010;
const int inf=2147483647;
const int mod=1000000007;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
int n,m,H,cnt=0;
int P(int x,int y){return m*(x-1)+y;}
struct Node
{
int v,type,x,y;
}a[Maxn<<1];
bool cmp(Node a,Node b){return a.v<b.v;}
int Pow(int x,int y)
{
if(!y)return 1;
if(y==1)return x;
int t=Pow(x,y>>1),re=(LL)t*t%mod;
if(y&1)re=(LL)re*x%mod;
return re;
}
int fa[Maxn],mx[Maxn],ans[Maxn];
int findfa(int x){return(fa[x]==x?x:fa[x]=findfa(fa[x]));}
void merge(int x,int y,int h)
{
int fx=findfa(x),fy=findfa(y);
if(fx!=fy)
{
ans[fy]=(LL)(ans[fy]+h-mx[fy])*(ans[fx]+h-mx[fx])%mod;
mx[fy]=h;
fa[fx]=fy;
}
}
int main()
{
n=read(),m=read(),H=read();
for(int i=1;i<=n;i++)
for(int j=1;j<m;j++)
a[++cnt].v=read(),a[cnt].x=i,a[cnt].y=j,a[cnt].type=0;
for(int i=1;i<n;i++)
for(int j=1;j<=m;j++)
a[++cnt].v=read(),a[cnt].x=i,a[cnt].y=j,a[cnt].type=1;
sort(a+1,a+1+cnt,cmp);
for(int i=1;i<=n*m;i++)fa[i]=i,mx[i]=-1,ans[i]=0;
for(