1.tower
【題目描述】
平面上有n個整點。如果將點(x0,y0)移動到(x1,y1),則需要的代價為|x0-x1|+|y0-y1|。求使得k(k=1…n)個點在同一位置上最少需要的代價。
【輸入檔案】
第一行1個正整數n ;
接下來n行,每行兩個正整數xi和yi,為第i個點的座標,不超過106。
【輸出檔案】
輸出共n行,第i行為使得有i個點在同一位置的最少代價。
【樣例輸入】
4 15 14
15 16
14 15
16 15
【樣例輸出】
0 2
3 4
【資料規模】
對於100%的資料,滿足1≤n≤50。
最優解必定是在(xi,yj)這些位置上的,因此只要列舉這些位置(共n2個),然後將所有點與這個位置的距離d[i]從小到大排序,然後s[i]=d[1]+d[2]+…+d[i]。那麼ans[k]=min。
#include
using
namespace
std;
int n,i,j,ans[52],x[52],y[52],k,d[52],sum;
int main()
for (i=1;i<=n;i++) printf("%d\n",ans[i]);
}
2.置換
題目描述:
n個數字,初始序列為1、2、3、4……n。現有m行n列的數字,每行為乙個置換操作。如某行操作的第i個數字為a[i],那麼就把原來序列中的第a[i]個數字放到現在這個序列的第i的位置上,然後組成新的序列。然後,看列表的第二行操作……、第三行操作……一直到最後一行操作,重複上面的操作。當最後一行的操作結束,組成了的序列又按照第一行來操作,然後第二行操作……第三行操作……一直迴圈下去,直到一共操作了k行為止。最後生成的這個序列就是我們最終的序列。
輸入格式:
第一行三個數,n,m和k。
接下來m行,每行n個數。
輸出格式:
一行,一共n個數,表示最終的禮品序列。n個數之間用乙個空格隔開,行尾沒有空格,需要回車。
輸入樣例:
7 5 8
6 1 3 7 5 2 4
3 2 4 5 6 7 1
7 1 3 4 5 2 6
5 6 7 3 1 2 4
2 7 3 4 6 1 5
輸出樣例:
2 4 6 3 5 1 7
資料範圍:
1<=n<=100;1<=m<=10;1<=k<=2^31-1。
對於50%的資料,保證k<=500。這些資料每個資料點8分,其他的資料每個資料點12分。
置換是迴圈往復的,並且我們可以發現雖然k很大,但是m<=10,那麼我們可以先預處理出a[i][j]表示第i次置換以後位置j上是原遞增序列中的哪乙個數,然後把k分成兩部分:k/m 和k%m現在把m次置換稱為乙個大置換,那大置換的次數就是k/m次,剩下的k%m次是依次置換。由於我們一開始已經預處理出每次置換乙個以後的序列,所以可以把a[m][1..n]和a[k%m][1..n]提取出來建立兩個矩陣matrix1、matrix2,設初始的序列(即遞增序列)ans,最終的序列就是ans*(matrix1^(k/m))*matrix2,注意順序不能顛倒,筆者就被這個坑了好久。。。。matrix1的k/m次方用快速冪求。
時間複雜度:o(n^3logk)
#include
using
namespace
std;
int n,m,k,i,j,x,t;
struct maa[12],b,c;
int read()while(c<48||c>57);
do x=(x<<1)+(x<<3)+(c^48),c=getchar();while(c>=48&&c<=57);
return f*x;
}ma operator *(ma x,ma y)
ma operator ^(ma x,int y)
void print(ma a,int x,int y)
int main()
for (i=1;i<=n;i++) b.a[1][i]=i;
for (i=1;i<=m;i++) c=c*a[i];
b=b*(c^(k/m));
for (i=1;i<=k%m;i++) b=b*a[i];
print(b,1,n);
}
jxy大佬不用矩陣,用乙個類似矩陣乘法的操作做到了o(nlogk),orz
#include
int n,m,k,tmp,i,j;
struct maa[12],ans;
ma operator *(ma x,ma y)
void calc(int num)
calc(num>>1);
ans=ans*ans;
if (num&1) ans=ans*a[m];
}int main()
calc(k/m);
tmp=k%m;
for (i=1;i<=n;i++) printf("%d ",ans.a[a[tmp].a[i]]);
}
3.數列
【題目描述】
給定乙個長度是n的數列a,我們稱乙個數列是完美的,當且僅當對於其任意連續自序列的和都是正的。現在你有乙個操作可以改變量列,選擇乙個區間[x,y]滿足ax+ax+1+…+ay<0,1小於x<=y小於n,令s=ax+ax+1+…+ay,對於ax-1和ay+1分別加上s,ax和ay分別減去s(如果x = y就減兩次).問最少幾次這樣的操作使得最終數列是完美的。
【輸入檔案】
第一行乙個數n,以下n個數。
【輸出檔案】
乙個數表示最少的操作次數,如果無解輸出-1。
【樣例輸入】
5 13
-3 -4
-5 62
【樣例輸出】
2 【樣例解釋】
首先選擇區間[2,4],之後數列變成1, 9, -4, 7, 50,然後選擇[3,3],數列變成1, 5, 4, 3, 50
【資料規模】
對於20%的資料,滿足1≤n≤5;
對於100%的資料,滿足1≤n≤105;1≤ | a[i] | ≤ 231-1。
首先乙個滿足條件的序列就是乙個字首和嚴格遞增的數列,
然後我們可以發現乙個重要的性質:操作[x,y]就是交換x-1和y的字首和!於是問題就簡單了:用最少的交換次數將字首和數列排序。這個問題可以通過簡單的找環解決。首先對問題進行離散化,然後看當前的置換中有幾個圈,如果有k個,那麼答案就是n-k。注意判斷無解的情況。
#include
using
namespace
std;
typedef
long
long ll;
const
int n=100003;
struct kka[n];
int i,x,ne[n],t,n,ans;
int read()while(c<48||c>57);
do x=(x<<1)+(x<<3)+(c^48),c=getchar();while(c>=48&&c<=57);
return f*x;
}bool cmp(kk x,kk y)
a[i].sum=a[i-1].sum+x;
a[i].id=i;
}if (a[n].sum<=0)
sort(a+1,a+n,cmp);
for (i=1;ifor (t=a[i].id;ne[t];t=ne[t]);
if (t!=i) ans++,ne[i]=t;
}printf("%d",ans);
}
NOIP模擬賽 老師
題目描述 一座有n層的教學樓裡有一些學生,第i 0 i n 層有studentsi個學生。你被給定了乙個數k,如果第i層有x個學生,那麼這一層需要 x k 個老師。你可以調整每個學生的樓層,但是每個學生至多只能調整一層,就是說第i層的學生只能去第i 1層 如果有的話 第i層 第i 1層 如果i 1 ...
5 27模擬題 擷取
給你n段線的長度,現在要你從他們上面切下k段來 切下的不能合併 使得這k段長度相等,並且最大。如若求出的答案小於0.01,則認為無解,輸出0.00。所有非整數都精確到了兩位,輸出亦然 1 n,k 10000 每條線段的長度都是在1到100000之間的實數 二分查詢,一般用於最小值的最大值,最大值的最...
5 27 女生賽總結
好的吧,真的是有史以來第一次出去比賽 好像大家都也還是給予厚望的,女生賽。前面過了兩個其實還好吧 最後卡,卡到兩三個題後來還是出不來了。我們刻意避開了 打鐵關 但是還是打鐵了qaq,zj說dp的方程明明都寫對了啊。他們t了那是因為暴力,這種錯法我還是第一次見啊。去之前自己還帶了自己列印的1 3部落格...