題目描述
我們稱一個矩陣是下降矩陣,當且僅當,矩陣的每一列都是嚴格下降的。很顯然,這個要求很苛刻,大多數矩陣都無法滿足。但是顯然如果消去一些行,一定可以使得這個矩陣變成下降矩陣。
現在給出一個n行m列的矩陣,請你求出最少消去多少行,可以使得這個矩陣變為下降矩陣。
現在給出一個n行m列的矩陣,請你求出最少消去多少行,可以使得這個矩陣變為下降矩陣。
輸入
輸入第一行包含兩個正整數n,m分別表示矩陣的行數和列數。(1<=n,m<=300)
接下來n行,每行有m個數,中間用空格隔開,每個數都小於2^31.
接下來n行,每行有m個數,中間用空格隔開,每個數都小於2^31.
輸出
輸出僅包含一個整數,即最少消去的行數。
樣例輸入 Copy
1 3
1 2 3
樣例輸出 Copy
0
把每一行元素看作一個向量,或者說一個"行元素"。題目要求的就是對於N個向量來說的最長的嚴格下降子序列長度,然后用N減去這個嚴格下降子序列長度就是答案了。方法與求LIS類似。
1 #include<bits/stdc++.h>
2 using namespace std; 3
4 int N,M; 5 int v[330][330]; 6 int f[330]={0}; 7 bool cmp(int di,int dj){ 8 for(int i=1;i<=M;++i){ 9 if(v[di][i] <= v[dj][i] ) return 0; 10 }return 1; 11 } 12 int main() 13 { 14 cin>>N>>M; 15 for(int i=1;i<=N;++i) 16 for(int j=1;j<=M;++j) 17 cin>>v[i][j]; 18 f[1]=1; 19 int ans=1; 20 for(int i=2;i<=N;++i){ 21 f[i]=1; 22 for(int j=1;j<i;++j){ 23 if(cmp(j,i)){ 24 f[i]=max(f[i],f[j]+1); 25 } 26 } 27 ans=max(ans,f[i]); 28 } 29 cout<<N-ans<<endl; 30 return 0; 31 }
題目描述
一天,Chika 對大小接近的點對產生了興趣,她想搞明白這個問題的樹上版本,你能幫助她嗎?Chika 會給 你一棵有根樹,這棵樹有 n 個結點,被編號為 1 n,1 號結點是根。每個點有一個權值,i 號結點的權值為 a[i]。如果 u 是 v 的祖先結點,並且 abs(a[u]−a[v]) ≤K,那么 (u,v) 被稱作一個“** 大小接近的點對 **”。 對於樹上的每個結點 i,你都需要計算以其為根的子樹中的“大小接近的點對”的數量。你需要知道:
(1) abs(x) 代表 x 的絕對值。
(2) 每個結點都是其自身的祖先結點.
(1) abs(x) 代表 x 的絕對值。
(2) 每個結點都是其自身的祖先結點.
輸入
輸入文件的第一行包含兩個整數 n (1≤n≤105) 和 k (1≤k≤109),代表樹中結點總數, 以及“大小接近的點對”的大小之差的上界。
第二行包含 n 個整數,第 i 個整數是 a[i] (1≤ a[i] ≤109),代表 i 號結點的權值。
第三行包含 n−1 個整數,第 i 個整數是 i+1 號結點的父結點。
第二行包含 n 個整數,第 i 個整數是 a[i] (1≤ a[i] ≤109),代表 i 號結點的權值。
第三行包含 n−1 個整數,第 i 個整數是 i+1 號結點的父結點。
輸出
輸出應該包含n行,每一行包括一個整數。第i行的整數代表以i為根的子樹中的“大小接近的點對”的數量。
樣例輸入 Copy
7 5
2 4 4 1 4 6 4
1 2 3 1 2 3
樣例輸出 Copy
19
11
5
1
1
1
1
比賽的時候推出來是主席樹了,奈何很久沒寫忘記關鍵步驟了= =
先跑dfs先序對節點重新編號,然后按照新編號依次update,問題就轉化為求在[L,R]編號區間內的滿足a[u]-K<=x<=a[u]+K的x的數目。
注意答案會爆int,很操蛋。
1 #include<bits/stdc++.h>
2 using namespace std; 3 #define LL long long
4 #define mid ((L+R)>>1)
5 const int maxn=100010; 6 int N,K; 7 LL ans[maxn]; 8 int a[maxn],idx[maxn],_idx[maxn],cur=0,sons[maxn]; 9 vector<int>g[maxn]; 10 int root[maxn]; 11 int tot=0,ch[maxn*50][2]; 12 int sum[maxn*50]; 13
14 void update(int pre,int &now,int L,int R,int val){ 15 tot++; 16 ch[tot][0]=ch[pre][0],ch[tot][1]=ch[pre][1]; 17 sum[tot]=sum[pre]+1,now=tot; 18 //cout<<"now="<<now<<" "<<pre<<endl;
19 if(L==R){ 20 return; 21 } 22 if(val<=mid){ 23 update(ch[pre][0],ch[now][0],L,mid,val); 24 } 25 else{ 26 update(ch[pre][1],ch[now][1],mid+1,R,val); 27 } 28 } 29 int ask(int pre,int now,int L,int R,int l,int r){ 30 if(L>=l && R<=r){ 31 return sum[now]-sum[pre]; 32 } 33 int res=0; 34 if(r<=mid) res=ask(ch[pre][0],ch[now][0],L,mid,l,r); 35 else if(l>mid) res=ask(ch[pre][1],ch[now][1],mid+1,R,l,r); 36 else{ 37 res=ask(ch[pre][0],ch[now][0],L,mid,l,r)+ask(ch[pre][1],ch[now][1],mid+1,R,l,r);; 38 } 39 return res; 40 } 41 /*void show(int id,int L,int R){ 42 cout<<L<<' '<<R<<' '<<sum[id]<<endl; 43 if(L==R)return; 44 if(ch[id][0])show(ch[id][0],L,mid); 45 if(ch[id][1])show(ch[id][1],mid+1,R); 46 }*/
47 void dfs(int u){ 48 idx[u]=++cur; 49 _idx[cur]=u; 50 sons[u]=1; 51 for(auto v:g[u])dfs(v),sons[u]+=sons[v]; 52 } 53 void solve(int u){ 54 ans[u]=ask(root[idx[u]-1],root[idx[u]-1+sons[u]],1,1000000000,max(1,a[u]-K),min(1000000000,a[u]+K)); 55 for(auto v:g[u]){ 56 solve(v); 57 ans[u]+=ans[v]; 58 } 59 } 60 int main(){ 61 cin>>N>>K; 62 for(int i=1;i<=N;++i)scanf("%d",a+i); 63 for(int i=2,fa;i<=N;++i){ 64 scanf("%d",&fa); 65 g[fa].push_back(i); 66 } 67 dfs(1); 68 for(int i=1;i<=N;++i){ 69 update(root[i-1],root[i],1,1000000000,a[_idx[i]]); 70 } 71 solve(1); 72 for(int i=1;i<=N;++i)printf("%lld\n",ans[i]); 73
74 return 0; 75 }
題目描述
咕咕最近在學習初等數論,並且對下取整函數產生了極大的興趣。下取整函數是指一個函數,自變量為 一個實數,因變量為一個整數,這個整數恰好是小於或等於自變量的最大的整數,通常記做 ⌊x⌋。例如, ⌊2.5⌋ = 2,⌊2⌋ = 2,⌊−2.5⌋ = −3。
咕咕發現,給定一個 a,並不是所有的自然數 n 都存在一個正整數 i 使得 ⌊n/i⌋ = a。那么,如果給定 l,r,咕咕好奇在區間 [l,r] 中有多少個正整數能使這個等式有正整數解 i 呢?
那么,聰明的你,你能告訴咕咕嗎?
咕咕發現,給定一個 a,並不是所有的自然數 n 都存在一個正整數 i 使得 ⌊n/i⌋ = a。那么,如果給定 l,r,咕咕好奇在區間 [l,r] 中有多少個正整數能使這個等式有正整數解 i 呢?
那么,聰明的你,你能告訴咕咕嗎?
輸入
第一行有一個整數 T(1 ≤ T ≤ 106),表示數據組數。接下來有 T 行,每行有三個數 a,l,r(1 ≤ a ≤ 1018,1 ≤ l ≤ r ≤ 1018),表示一組詢問。
輸出
輸出 T 行,對每組詢問,輸出一個整數表示答案。
樣例輸入 Copy
4
5 7 10
7 39 42
1000 1000 1000
27 100 1000
樣例輸出 Copy
1
2
1
617
提示
數據范圍
當 n = 39,a = 7 時,能找到 i = 5 使得 ⌊39 /5 ⌋ = 7。
當 n = 39,a = 7 時,能找到 i = 5 使得 ⌊39 /5 ⌋ = 7。
規律題,找規律or打表可以發現,這些滿足條件的數字可以按照k*a分類,
1,2......a......2a,2a+1......3a,3a+1,3a+2............a*a,....a*a+a-1......(a+1)*a......k*a......
規律很容易發現,就是找不同的正整數k,那么從k*a開始往后的k個數字(包括k*a)只要在區間里面都是滿足條件的,k等於多少就有多少個滿足條件的數字,但注意當k>a的時候最多也只有a個數字而不是k個數字了。
利用容斥思想,找出[1,r]內的個數和[1,l-1]的個數做差就是答案。
code:
1 #include<bits/stdc++.h>
2 using namespace std; 3 #define LL long long
4 LL T,a,l,r; 5 LL solve(LL n){ 6 if(n<1) return 0; 7 LL ans=0; 8 LL div=n/a,rem=n%a; 9 if(div<=a){ 10 ans+= div*(div-1)/2; 11 if(div*a+div-1<=n){ 12 ans+=div; 13 } 14 else{ 15 ans+=(n-div*a+1); 16 } 17 } 18 else{ 19 ans+=(1+a)*a/2; 20 ans+=(div-a-1)*a; 21 if(div*a+a-1<=n){ 22 ans+=a; 23 } 24 else{ 25 ans+=(n-div*a+1); 26 } 27 } 28 return ans; 29 } 30 int main() 31 { 32 scanf("%lld",&T); 33 while(T--){ 34 scanf("%lld%lld%lld",&a,&l,&r); 35 printf("%lld\n",solve(r)-solve(l-1)); 36 } 37 return 0; 38 }
問題 I: Childhood dream
時間限制: 1 Sec 內存限制: 256 MB提交: 63 解決: 18
[提交] [狀態] [討論版] [命題人:zhd]
題目描述
你童年時期就有一個夢想,想要加入 ACM(Association of Calculation and Magic),今天,這個機會終於 來了。
但是 ACM 只想要哪些天賦異稟的人, 比如像 tourist,他們給了你一道題來檢測你是否足夠機智。
猜一個長度為 m 數字串,總共有 n 個提示串,解釋如下:
8640 0A2B
A 前面的數字說明與答案相比,有多少個位置上的數字是相同的。 B 前面的數字說明與答案相比,有多 少個數字是相同的,但是位置不一樣。
0 A 就表示給出的串沒有任何位置和答案是相同的。 2 B 就表示給出的串中有兩個數字和答案相同,但 是位置不一樣。
所以,對於上面那個提示串 6457 是一個合理的答案,但是 1234 並不是。
現在給你 N(N<=100) 個提示串(如上所示),你需要去找到一個數字串來符合每一個提示串的要求。
提示串中的每個數字都是不同的,即一個串中不會存在相同的數字。
你能解決這個問題並加入 ACM 嗎?
但是 ACM 只想要哪些天賦異稟的人, 比如像 tourist,他們給了你一道題來檢測你是否足夠機智。
猜一個長度為 m 數字串,總共有 n 個提示串,解釋如下:
8640 0A2B
A 前面的數字說明與答案相比,有多少個位置上的數字是相同的。 B 前面的數字說明與答案相比,有多 少個數字是相同的,但是位置不一樣。
0 A 就表示給出的串沒有任何位置和答案是相同的。 2 B 就表示給出的串中有兩個數字和答案相同,但 是位置不一樣。
所以,對於上面那個提示串 6457 是一個合理的答案,但是 1234 並不是。
現在給你 N(N<=100) 個提示串(如上所示),你需要去找到一個數字串來符合每一個提示串的要求。
提示串中的每個數字都是不同的,即一個串中不會存在相同的數字。
你能解決這個問題並加入 ACM 嗎?
輸入
第一行兩個數字,n(n<=100) 和 m(m<=9), 提示串的數量以及目標字符串的長度。
然后是 n 行,每行的格式如下:
s x y
s 是提示串,x 是 A 前的數字,y 是 B 前的數字,等同於:
s xAyB
然后是 n 行,每行的格式如下:
s x y
s 是提示串,x 是 A 前的數字,y 是 B 前的數字,等同於:
s xAyB
輸出
一行,目標串。
數據保證答案唯一。
數據保證答案唯一。
樣例輸入 Copy
6 4
5164 3 0
5174 3 0
5194 3 0
5124 3 0
5134 3 0
5104 3 0
樣例輸出 Copy
5184
暴力搜索,由於不可行的情況很多,減枝會減去很多方案,所以直接搜完事。
#include<bits/stdc++.h>
using namespace std; char str[115][15]; int A[115],B[115],tot[115][10]; int N,M; int c[15]; bool ok=0; bool check(int n,int type){ for(int i=1;i<=N;++i){ int _A=0,_B=0; for(int j=0;j<n-1;++j){ if(str[i][j]-'0' == c[j+1]){ _A++; } else{ if(tot[i][c[j+1]]){ _B++; } } } if(type==0 &&(_A>A[i] || _B>B[i] )) return 0; if(type==1 &&(_A!=A[i] || _B!=B[i])) return 0; } return 1; } void dfs(int u){ if(ok)return; if(!check(u,0)){ return; } if(u==M+1){ if(check(M+1,1)){ ok=1; for(int i=1;i<=M;++i)cout<<c[i];cout<<endl; } return; } else{ for(int i=0;i<10;++i){ c[u]=i; dfs(u+1); } } } int main() { cin>>N>>M; for(int i=1;i<=N;++i){ cin>>str[i]>>A[i]>>B[i]; } for(int i=1;i<=N;++i){ for(int j=0;j<M;++j){ tot[i][str[i][j]-'0']++; } } dfs(1); return 0; }
