申請SAE

如果您發現本博客的外觀很難看,那是因為部分外觀文件被中國.國家.防火.牆屏.蔽所致!
請翻~牆!

我的Wordpress博客的地址: http://zhuyf.tk/

2012年1月3日 星期二

網絡流入門試題 [最大流]運輸問題1 maxflowa

題目連結:http://cogs.yeefanblog.tk/t/11
Title: 运输问题1
Input: maxflowa.in
Output: maxflowa.out
Time Limit: 1000 ms
Memory Limit: 128 MB
Level: ★★☆
【问题描述】
    一个工厂每天生产若干商品,需运输到销售部门进行销售。从产地到销地要经过某些城镇,有不同的路线可以行走,每条两城镇间的公路都有一定的流量限制。请你计算,在不考虑其它车辆使用公路的前提下,如何充分利用所有的公路,使产地运输到销地的商品最多,最多能运输多少商品。
【输入格式】
输入文件有若干行
第一行,一个整数n,表示共有n个城市(2<=n<=100)
下面有n行,每行有n个数字。第p行第q列的数字表示城镇p与城镇q之间有无公路连接。数字为0表示无,大于0表示有公路,且该数字表示该公路流量。
【输出格式】
输出文件有一行
第一行,1个整数n,表示最大流量为n。
【输入输出样例】
输入文件名: maxflowa.in
6
0 4 8 0 0 0
0 0 4 4 1 0
0 0 0 2 2 0
0 0 0 0 0 7
0 0 0 6 0 9
0 0 0 0 0 0
输出文件名:maxflowa.out
8

【分析】
基礎的最大流問題。
由於源點沒有入度、匯點沒有出度,所以由樣例可以看出1號的源點,N號是匯點。
剩下就是用Ford-Fulkerson方法求解最大流即可。
《算法導論》上,Ford-Filkerson方法的偽代碼描述是:
FORD_FULKERSON(G,s,t)
1 for each edge(u,v)∈E[G]
2 do f[u,v] <— 0
3 f[v,u] <— 0
4 while there exists a path p from s to t in the residual network Gf
5 do cf(p) <— min{ cf(u,v) : (u,v) is in p }
6 for each edge(u,v) in p
7 do f[u,v] <— f[u,v]+cf(p)
8 f[v,u] <— -f[u,v]
        

【我的代碼】

C++语言: Codee#25004
001 /*
002 *Problem:http://cogs.yeefanblog.tk/t/11
003 *Author:Yee-fan Zhu
004 *Website:http://www.zhuyf.tk/
005 *Method:網絡流 最大流 Full-Fulkerson
006 */
007 #include <iostream>
008 #include <cstdio>
009 #include <cstdlib>
010 #include <cstring>
011 #include <queue>
012 using namespace std;
013
014 const int INF=0x7ffffff;
015 const int MAXN=101;
016 int Map[MAXN][MAXN];
017 int Father[MAXN];
018 bool Used[MAXN];
019 int Ans;
020 int N,M;
021 int S,T;
022
023 void Ford_Fulkerson()
024 {
025     while(1)
026     {
027         queue<int>Q;
028         memset(Used,0,sizeof(Used));
029         memset(Father,0,sizeof(Father));
030
031         int now;
032         Used[S]=true;
033         Q.push(S);
034         while(!Q.empty())
035         {
036             now=Q.front();
037             Q.pop();
038             if(now==T)
039                 break;
040             for (int i=1;i<=N;i++)
041             {
042                 if(Map[now][i] && !Used[i])
043                 {
044                     Father[i]=now;
045                     Used[i]=true;
046                     Q.push(i);
047                 }
048             }
049         }
050
051         if(!Used[T])// There is no Augmenting Path.
052             break;
053
054         int u;
055         int Min=INF;
056         for (u=T;u!=S;u=Father[u])
057         {
058             if(Map[Father[u]][u]<Min)
059                 Min=Map[Father[u]][u];
060         }
061
062         for (u=T;u!=S;u=Father[u])
063         {
064             Map[Father[u]][u]-=Min;
065             Map[u][Father[u]]+=Min;
066         }
067
068         Ans+=Min;
069     }
070 }
071
072 void init()
073 {
074     scanf("%d\n",&N);
075     M=0;
076     memset(Map,0,sizeof(Map));
077
078     int v;
079     for (int i=1;i<=N;i++)
080     {
081         for (int j=1;j<=N;j++)
082         {
083             scanf("%d",&v);
084             Map[i][j]=v;
085             if(v)
086                 M++;
087         }
088     }
089     S=1;
090     T=N;
091     return;
092 }
093
094 int main()
095 {
096     freopen("maxflowa.in","r",stdin);
097     freopen("maxflowa.out","w",stdout);
098     init();
099     Ford_Fulkerson();
100     printf("%d\n",Ans);
101     return 0;
102 }

2012年1月2日 星期一

[並查集]NOI2001 食物鏈 eat 解題報告

Title: 食物链    題目連結:COGS
Input: eat.in
Output: eat.out
Time Limit: 1000 ms
Memory Limit: 128 MB
Level: ★★☆

动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形。A吃B, B吃C,C吃A。
现有N个动物,以1-N编号。每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种。
有人用两种说法对这N个动物所构成的食物链关系进行描述:
  • 第一种说法是“1 X Y”,表示X和Y是同类。
  • 第二种说法是“2 X Y”,表示X吃Y。
此人对N个动物,用上述两种说法,一句接一句地说出K句话,这K句话有的是真的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。
  1. 当前的话与前面的某些真的话冲突,就是假话;
  2. 当前的话中X或Y比N大,就是假话;
  3. 当前的话表示X吃X,就是假话。
你的任务是根据给定的N(1<=N<=50,000)和K句话(0<=K<=100,000),输出假话的总数。

输入文件
第一行是两个整数N和K,以一个空格分隔。
以下K行每行是三个正整数 D,X,Y,两数之间用一个空格隔开,其中D表示说法的种类。
  • 若D=1,则表示X和Y是同类。
  • 若D=2,则表示X吃Y。
输出文件
只有一个整数,表示假话的数目。
输入样例
100 7
1 101 1
2 1 2
2 2 3
2 3 3
1 1 3
2 3 1
1 5 5
输入文件
输出样例
3
样例说明
对7句话的分析
  • 1 101 1 假话
  • 2 1 2 真话
  • 2 2 3 真话
  • 2 3 3 假话
  • 1 1 3 假话
  • 2 3 1 真话
  • 1 5 5 真话

「分析」

本題是並查集的經典應用。
每次判斷時,前兩個條件都能O(1)判斷,關鍵在於第3個條件。
由於無法判斷可以另外虛設2*N個物種,分別表示能吃第i個物種的物種和被第i個物種所吃的物種。那麼剩下就是裸並查集了,每次合併就把那個三角環依次合併即可。

「我的代碼」

 

C++语言: Codee#24995
001 /*
002 *Problem: NOI2001-eat
003 *Author: Yee-fan Zhu
004 *Time: Jan 02,2012
005 *Method: UFS
006 */
007 #include <iostream>
008 #include <cstdlib>
009 #include <cstdio>
010 using namespace std;
011 const int MAX=150010;
012
013 int N,K;
014 int Ani[MAX];
015 int Eat[MAX];
016 int Eaten[MAX];
017 int False=0;
018
019 int UFS_Find(int x)
020 {
021     int t,p;
022     p=x;
023     while(Ani[p]!=p)
024         p=Ani[p];
025     while(Ani[x]!=x)  //Compress Path
026     {
027         t=Ani[x];
028         Ani[x]=p;
029         x=t;
030     }
031     return p;
032 }
033
034 bool UFS_Check(int a,int b)
035 {
036     int x=UFS_Find(a);
037     int y=UFS_Find(b);
038     return (x==y);
039 }
040
041 void UFS_Merge(int a,int b)
042 {
043     Ani[UFS_Find(b)]=UFS_Find(a);
044 }
045
046 void init()
047 {
048     scanf("%d %d\n",&N,&K);
049     for (int i=1;i<=N;i++)
050     {
051         int x=N+i;
052         int y=N*2+i;
053         Ani[i]=i,Ani[x]=x,Ani[y]=y;
054         Eaten[i]=x,Eat[i]=y;
055         Eaten[x]=y,Eat[x]=i;
056         Eaten[y]=i,Eat[y]=x;
057     }
058 }
059
060 void work()
061 {
062     int D,X,Y;
063     for (int i=1;i<=K;i++)
064     {
065         scanf("%d %d %d\n",&D,&X,&Y);
066         if(X>N || Y>N)
067         {
068             False++;
069             continue;
070         }
071         if(D==2 && X==Y)
072         {
073             False++;
074             continue;
075         }
076
077         if(D==1)
078         {
079             if(UFS_Check(X,Y))
080                 continue;
081             if(UFS_Check(Eat[X],Y) ||  UFS_Check(Eaten[X],Y) )
082             {
083                 False++;
084                 continue;
085             }
086
087             UFS_Merge(X,Y);
088             UFS_Merge(Eaten[X],Eaten[Y]);
089             UFS_Merge(Eat[X],Eat[Y]);
090             continue;
091         }
092
093         if(D==2)
094         {
095             if(UFS_Check(Eat[X],Y))
096                 continue;
097
098             if(UFS_Check(X,Y) || UFS_Check(Eaten[X],Y))
099             {
100                 False++;
101                 continue;
102             }
103
104             UFS_Merge(Eat[X],Y);
105             UFS_Merge(X,Eaten[Y]);
106             UFS_Merge(Eaten[X],Eat[Y]);
107             continue;
108         }
109     }
110 }
111
112 int main()
113 {
114     freopen("eat.in","r",stdin);
115     freopen("eat.out","w",stdout);
116     init();
117     work();
118     printf("%d\n",False);
119     return 0;
120 }

2011年12月26日 星期一

[並查集]HAOI 破譯密文 encrypt 解題報告

【題目描述】  查看題目
原文鏈接:http://yeefan.tk/blog/haoi-encrypt/
資訊的明文是由0利1組成的非空序列。但在網絡通信中,為了資訊的安全性,常對明文進行加密,用密文進行傳輸。密文是由0、1和若干個密碼字母組成,每個密碼字母代表不同的01串,例如,密文二011a0bf00a01。密碼破譯的關鍵是確定每個密碼的含義。
經過長期統計分析,現在知道了每個密碼的固定長度,如今,我方又截獲了敵方的兩段密文S1和S2,並且知道S1二S2,即兩段密文代表相同的明文。你的任務是幫助情報人員對給定的兩段密文進行分析,看一看有多少種可能的明文。
【輸入文件】
第1行: S1 (第1段密文)
第2行: S2 (第2段密文)
第3行: N (密碼總數, N<=26)
第4—N+3行: 字母i 長度i (密碼用小寫英文字母表示, 密碼長度<=100)

【輸出文件】
M(表示有M種可能的明文)

【輸入輸出樣例】
encrypt.in
100ad1
cc1
4
a 2
d 3
c 4
b 50
encrypt.out
2
【約束條件】
明文的長度<=10000

【分析】
既然每個密文代表一段明文,那我們可以把密文展開
如樣例的:
100ad1
cc1
4
a 2
d 3
c 4
b 50
我們就可以展開成
1 0 0 a1 a2 d1 d2 d3 1
c1 c2 c3 c4 c1 c2 c3 c4 1
那麼問題就成了在這麼一串數中找出有多少個數不定集合.
即c1代表1 c2代表0 c3代表0
但是 c4和a1共同代表什麼呢,這是問題的關鍵,這就用到了並查集:
首先 1 0 a1 a2…d2 d3都是獨立的集合
從i=1開始向右掃描
先把1所在的集合和c1所在的集合歸成一類,
0所在的集合和c2所在的集合歸成一類
….
最後一定是
代表0的字母有一個集合
代表1的字母有一個集合
不能確定代表什麼的有x個集合
因為每個集合代表的數字要麼是1要麼是0有兩種情況
所以兩個集合有4種情況
三個集合有8種情況
x個集合有2^x種情況
所以我們只需要用並查集算出有幾個非0或1的集合,再累乘後輸出即可
注意:有一個密文既對應0也對應1,這種情況構不成任何正確的明文,所以應當輸出0。

【我的代碼】
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <cstring>
using namespace std;
int num[30];
 
const char base='a'-1;
const int MAXN=3000;
int Letter[30];//每個密碼的密碼長度
int Num[30][102];
char S1[105];
char S2[105];
int N;//密碼總數
int T=0;//不定集合的數量
int Sum=0;//最終結果
int M=0;
int DealA[MAXN]={0};
int DealB[MAXN]={0};
int Num0;
int Num1;
int Len=0;
 
class Node
{
public:
 int parent;
 int count;
}UFS[MAXN];
 
void UFS_Init(int i)
{
 UFS[i].count=1;
 UFS[i].parent=i;
}
 
int UFS_Find(int x)
{
 int i=x;
 while(i!=UFS[i].parent)
  i=UFS[i].parent;
 
 int j=x;
 while(j!=i)
 {
  int tmp=UFS[j].parent;
  UFS[j].parent=i;
  j=tmp;
 }
 return i;
}
 
void UFS_Merge(int x,int y)
{
 x=UFS_Find(x);
 y=UFS_Find(y);
 if(x==y)
  return;
 
 if(UFS[x].count>UFS[y].count)
 {
  UFS[y].parent=x;
  UFS[x].count+=UFS[y].count;
 }
 else
 {
  UFS[x].parent=y;
  UFS[y].count+=UFS[x].count;
 }
}
 
void init()
{
 scanf("%s\n%s\n",&S1,&S2);
 scanf("%d\n",&N);
 memset(Letter,0,sizeof(Letter));
 char cTmp;
 int iTmp;
 for (int i=1;i<=N;i++)
 {
  scanf("%c %d\n",&cTmp,&iTmp);
  Letter[cTmp-base]=iTmp;
 } 
 
 for(int i=1;i<=26;i++)
 {
  for (int j=1;j<=Letter[i];j++)
  {
   M++;
   Num[i][j]=M;
   UFS_Init(M);
  }
 }
 
 M++;
 Num0=M;
 UFS_Init(M);
 
 M++;
 Num1=M;
 UFS_Init(M);
 
 int top=0;
 for (unsigned int i=0;i<strlen(S1);i++)
 {
  if(isalpha(S1[i]))
  {
   for (int j=1;j<=Letter[ S1[i]-base ]; j++)
   {
    top++;
    DealA[top]=Num[S1[i]-base][j];
   }
  }
  else
  {
   if(S1[i]=='0')
   {
    top++;
    DealA[top]=Num0;
   }
   else
   {
    top++;
    DealA[top]=Num1;
   }
  }
 }
 
 Len=top;
 top=0;
 for (unsigned int i=0;i<strlen(S2);i++)
 {
  if(isalpha(S2[i]))
  {
   for (int j=1;j<=Letter[ S2[i]-base ]; j++)
   {
    top++;
    DealB[top]=Num[S2[i]-base][j];
   }
  }
  else
  {
   if(S2[i]=='0')
   {
    top++;
    DealB[top]=Num0;
   }
   else
   {
    top++;
    DealB[top]=Num1;
   }
  }
 } 
}
 
int work()
{
 for(int i=1;i<=Len;i++)
 {
  UFS_Merge(DealA[i],DealB[i]);
 }
 
 if(UFS_Find(Num0)==UFS_Find(Num1))
 {
  return 0;
 }
 
 bool Used[MAXN];
 memset(Used,0,sizeof(Used));
 
 int Find_Num0=UFS_Find(Num0);
 int Find_Num1=UFS_Find(Num1);
 for(int i=1;i<=Len;i++)
 { 
  int tmp=UFS_Find(DealA[i]);
  if(tmp==Find_Num0 || tmp==Find_Num1 || Used[tmp])
   continue;
 
  T++;
  Used[tmp]=true;
 }
 
 for(int i=1;i<=Len;i++)
 {
  int tmp=UFS_Find(DealB[i]);
  if(tmp==Find_Num0 || tmp==Find_Num1 || Used[tmp])
   continue;
 
  T++;
  Used[tmp]=true;
 }
 
 Sum=1;
 for (int i=1;i<=T;i++)
  Sum*=2;
 return Sum;
}
 
int main()
{
 freopen("encrypt.in","r",stdin);
 freopen("encrypt.out","w",stdout);
 init();
 printf("%d\n",work());
 return 0;
}

2011年12月19日 星期一

[最短路徑]USACO Silver09 找工作 jobhunt 解題報告

問題描述:
貝茜牛身無分文了,她正忙着找工作。農夫約翰知道這個情況,他想讓他的牛去周遊世界,於是他推行了一個規則:在他的牛到另 一個城市工作之前,她們只能在一個城市掙得 D ( 1 <= D <= 1,000 )美元。不管怎樣,貝茜可以在別的城市工作過之後,再返回到某個城市,並在這個城市再掙 D 美元,她可以無限次數地這樣做。
貝茜牛的世界包括 P ( 1 <= P <= 150 )條單向邊,這些邊連接着 C ( 2 <= C <= 220 )個城市,城市按 1 到 C 的順序編號,貝茜牛目前正待在 S 城 (1 <= S <= C) 。單向邊 i 從城市 A_i 連到城市 B_i ,其中 1 <= A_i <= C; 1 <= B_i <= C ,在路上不花費任何代價。
爲了幫助貝茜,約翰授權它使用他的私人噴氣飛機服務。這項服務配置了 F 條航綫,每條航綫是由城市 J_i 到城市 K_i (1 <=J_i <= C; 1 <= K_i <= C) 的單向航綫,且在該航綫上的費用是 T_i( 1 <= T_i <= 50,000 ) 美元,如果貝茜牛手頭沒有現錢,它可以將來掙到錢之後再支付飛行費用。
只要它願意,貝茜可以隨時隨地選擇退出。不限時間,假定它所有去過的城市都能掙足 D 美元,最後貝茜最多能得到多少錢?如果這個數目沒有限制的話輸出 -1 。
程序名:jobhunt
輸入格式:
第1行:五個空格隔開的整數,D,P,C,F,S;
第2至P+1行:第i行包括兩個空格隔開的整數,表示從城市A_i到B_i有一條單向邊。
第P+2至P+F+1行:第P+i行包括三個空格隔開的整數,表示從城市J_i到T_i有一條單向航綫,費用是T_i。
輸入樣例:(jobhunt.in):
100 3 5 2 1
1 5
2 3
1 4
5 2 150
2 5 120
輸入樣例解釋:這個世界有5個城市,三條有向邊,和兩條飛行航綫,貝茜從城市1開始,在每個城市它能最多掙到100美元。
輸出格式:
只有一行,一個整數,表示在遵守規則的情況下,它最多能得到多少錢。
輸出樣例:(jobhunt.out):
250
輸出樣例解釋:貝茜能從城市1→城市5→城市2→城市3,最後共得到4*100 - 150 = 250美元。
「分析」
單源最短路問題,賺錢是負權,航費是正權,用SPFA處理負邊權即可。
「我的代碼」
#include "cstdio"
#include "iostream"
#include "cstdlib"
#include "queue"
using namespace std;
const int MAX=230;
int Map[MAX][MAX];
int dist[MAX];
int times[MAX];
bool flag[MAX];
const int MAXN=1000000000;
int D;//在每個城市最多掙得D美金
int P;//P條單向邊
int C;//C個城市
int F;//F個單項航線
int S;//源點
typedef queue QUEUE;
void init()
{
 scanf("%d %d %d %d %d\n",&D,&P,&C,&F,&S);
 for (int i=1;i<=C;i++)
  for (int j=1;j<=C;j++)
   Map[i][j]=MAXN;
 for (int i=1;i<=C;i++)
  Map[i][i]=0;
 for (int i=1;i<=P;i++)
 {
  int a,b;
  scanf("%d %d\n",&a,&b);
  Map[a][b]=-D;
 }
 for (int i=1;i<=F;i++)
 {
  int a,b,c;
  scanf("%d %d %d\n",&a,&b,&c);
  if(Map[a][b]==MAXN)
  {
   Map[a][b]=c-D;
  }
 }
 return;
}
QUEUE Q;
void SPFA()
{
 for (int i=1;i<=C;i++)
  dist[i]=MAXN,flag[i]=false,times[i]=0;
 dist[S]=-D;
 Q.push(S);
 int x;
 while(Q.size())
 {
  x=Q.front();
  Q.pop();
  flag[x]=false;
  for(int i=1;i<=C;i++)
  {
   int tmp=dist[x]+Map[x][i];
   if(tmpC)
     {
      printf("-1\n");
      return;
     }
    }
   }
  }
 }
 int Max=MAXN;
 for (int i=1;i<=C;i++)
  if(Max>dist[i])
   Max=dist[i];
 printf("%d\n",-Max);
 return;
}
int main()
{
 freopen("jobhunt.in","r",stdin);
 freopen("jobhunt.out","w",stdout);
 init();
 SPFA();
 return 0;
}

2011年12月17日 星期六

[二分查找]NOIP2011提高組:聰明的質檢員 qc 解題報告

【問題描述】
試題檢視:GoogleDocs
小 T 是一名質量監督員,最近負責檢驗一批礦產的質量。這批礦產共有 n 個礦石,從 1 到 n 逐一編號,每個礦石都有自己的重量 wi 以及價值 vi。檢驗礦產的流程是:
1、給定 m個區間[Li,Ri];
2、選出一個參數 W;
3、對於一個區間[Li,Ri],計算礦石在這個區間上的檢驗值 Yi : 




若這批礦產的檢驗結果與所給標準值 S 相差太多,就需要再去檢驗另一批礦產。小 T 不想費時間去檢驗另一批礦產,所以他想通過調整參數 W 的值,讓檢驗結果儘可能的靠近標準值 S,即使得 S-Y的絕對值最小。請你幫忙求出這個最小值。
【輸入】
輸入文件 qc.in。
第一行包含三個整數n,m,S,分別表示礦石的個數、區間的個數和標準值。
接下來的n 行,每行2 個整數,中間用空格隔開,第i+1 行表示i 號礦石的重量wi 和價值vi 。
接下來的m 行,表示區間,每行2 個整數,中間用空格隔開,第i+n+1 行表示區間[Li,Ri]的兩個端點Li 和Ri。注意:不同區間可能重合或相互重疊。
【輸出】
輸出文件名爲qc.out。
輸出只有一行,包含一個整數,表示所求的最小值。
【輸入輸出樣例】
qc.in
5 3 15
1 5
2 5
3 5
4 5
5 5
1 5
2 4
3 3
qc.out
10
【輸入輸出樣例說明】
當W 選4 的時候,三個區間上檢驗值分別爲20、5、0,這批礦產的檢驗結果爲25,此時與標準值S 相差最小爲10。
【數據範圍】
對於10%的數據,有1≤n,m≤10;
對於30%的數據,有1≤n,m≤500;
對於50%的數據,有1≤n,m≤5,000;
對於70%的數據,有1≤n,m≤10,000;
對於100%的數據,有1≤n,m≤200,000,0 < wi, vi≤10^6,0 < S≤10^12,1≤Li≤Ri≤n。

 【分析】
本題的正解是二分W,從0~MaxW+1二分。計算Y時要先預處理,把所有大於W的礦石記錄下來,然後再計算每個區間的值。

二分結束後,找出Min{Get(Right),Get(Left)}輸出即可。

【我的代碼】
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
int N,M;
long long S;
const int MAXN=200001;
int W[MAXN];
int V[MAXN];
int L[MAXN];
int Sum[MAXN];
int R[MAXN];
long long TV[MAXN];
int TN[MAXN];
  
void init()
{
    Sum[0]=0;
    cin>>N>>M>>S;
    for (int i=1;i<=N;i++)
    {
        cin>>W[i]>>V[i];
        Sum[i-1]=W[i];
    }
    for (int i=1;i<=M;i++)
        cin>>L[i]>>R[i];
    sort(Sum,Sum+N);
    Sum[N]=Sum[N-1]+1;
}

long long Get(int w)
{
    long long res=0;
    TV[0]=0;
    TN[0]=0;
    for (int i=1;i<=N;i++)
    {
        if(W[i]>=w)
        {
            TV[i]=TV[i-1]+V[i];
            TN[i]=TN[i-1]+1;
            continue;
        }
        else
        {
            TV[i]=TV[i-1];
            TN[i]=TN[i-1];
        }
    }
  
    for (int i=1;i<=M;i++)
    {
        int tl=L[i];
        int tr=R[i];
        long long Temp=(TN[tr]-TN[tl-1])*(TV[tr]-TV[tl-1]);
        res+=Temp;
    }
  
    return res;
}

long long Abs(long long t)
{
    if(t>0)
        return t;
    else
        return -t;
}

void dichotomy()
{
    int Right;
    int Left;
    for (Left=0,Right=N;Left+1<Right;)
    {
        long long Temp=Get(Sum[(Right+Left)/2]);
        if(Temp>=S)
            Left=(Left+Right)/2;
        else
            Right=(Left+Right)/2;
    }
  
    long long TW1,TW2;
    TW1=Abs(Get(Sum[Right])-S);
    TW2=Abs(Get(Sum[Left])-S);
    if(TW2<TW1)
    {
        TW1=TW2;
    }
    cout<<TW1<<endl;
}  

int main()
{
    freopen("qc.in","r",stdin);
    freopen("qc.out","w",stdout);
    init();
    dichotomy();
    return 0;
}