記2018/4/29 qbxt 測試
記 2018/4/29 qbxt 測試(提高基礎班)
簡單的 NOIP 模擬賽
競賽時間: 2018 年 4 月 29 日 13:30-17:00
題目名稱 | 乘法 | 求和 | 計數 |
輸入文件名 | mul.in | sum.in | count.in |
輸出文件名 | mul.out | sum.out | count.in |
每個測試點時限 | 1 sec | 4 sec | 1 sec |
內存限制 | 128MB |
128MB | 128MB |
測試點數目 | 10 | 10 | 10 |
每個測試點分值 | 10 | 10 | 10 |
是否有部分分 | 無 | 無 | 無 |
題目類型 | 傳統 | 傳統 | 傳統 |
T1 期望得分:100;實際得分:100
乘法
【問題描述】
給定正整數n,m,p,你需要輸出 n * m 對 p 取模後的值
【輸入文件】
輸入文件為 mul.in
輸入為一行 n, m, p
【輸出文件】
輸出文件為 mul.out
輸出一行為一個整數,為所求的答案
【輸入輸出樣例】
mul.in | mul.out |
11 22 10 | 2 |
【數據規模和約定】
對於30%的數據,n, m, p <=10000;
對於60%的數據,n, m, p <= 109
對於100%的數據, n, m, p <= 1018
【一些提示】
以下是一些對取模操作的介紹:
一個整數a對一個整數p取模的值,是一個不超過p的非負整數b,並且a-b是p的倍數。可以證明,滿足條件的b有且只有一個;
一些運算在取模前後仍然成立,例如:
兩個數的和對p取模的值等於兩個數先對p取模,再求和,在取模;
兩個數的乘積對p取模的值等於兩個數先對p取模,再求乘積,再取模
但兩個數的除法沒有類似的性質
思路:快速乘(類似於快速冪) or 高精
#include<iostream> #include<cstring> #include<cstdio> using namespace std; long long n, m, p; long long Mul(long long x, long long y){ long long快速乘res = 0; x %= p; y %= p; while(y) { if(y & 1) res = (res+x) % p; x = (x+x) % p; y >>= 1; } return res; } int main() { //freopen("mul.in","r",stdin); //freopen("mul.out","w",stdout); cin >> n >> m >> p; cout<< Mul(n, m); //fclose(stdin); fclose(stdout); return 0; }
#include<iostream> #include<algorithm> #include<cstring> #include<cstdio> namespace BigInteger { #define maxn 10005 using std::sprintf; using std::string; using std::max; using std::istream; using std::ostream; struct Big_integer { int d[maxn],len; void clean() { while(len>1&&!d[len-1]) len--; } Big_integer() { memset(d,0,sizeof(d)); len=1; } Big_integer(int num) { *this=num; } Big_integer(char* num) { *this=num; } Big_integer operator = (const char* num) { memset(d,0,sizeof(d)); len=strlen(num); for(int i=0;i<len;i++) d[i]=num[len-1-i]-‘0‘; clean(); return *this; } Big_integer operator = (int num) { char s[10005]; sprintf(s,"%d",num); *this=s; return *this; } Big_integer operator + (const Big_integer& b) { Big_integer c=*this; int i; for(i=0;i<b.len;i++) { c.d[i]+=b.d[i]; if(c.d[i]>9) { c.d[i]%=10; c.d[i+1]++; } } while(c.d[i]>9) { c.d[i++]%=10; c.d[i]++; } c.len=max(len,b.len); if(c.d[i]&&c.len<=i) c.len=i+1; return c; } Big_integer operator - (const Big_integer& b) { Big_integer c=*this; int i; for(i=0;i<b.len;i++) { c.d[i]-=b.d[i]; if(c.d[i]<0) { c.d[i]+=10; c.d[i+1]--; } } while(c.d[i]<0) { c.d[i++]+=10; c.d[i]--; } c.clean(); return c; } Big_integer operator * (const Big_integer& b) const { int i,j; Big_integer c; c.len=len+b.len; for(j=0;j<b.len;j++) for(i=0;i<len;i++) c.d[i+j]+=d[i]*b.d[j]; for(i=0;i<c.len-1;i++) { c.d[i+1]+=c.d[i]/10; c.d[i]%=10; } c.clean(); return c; } Big_integer operator % (const Big_integer& b) { int i,j; Big_integer a=0; for(i=len-1;i>=0;i--) { a=a*10+d[i]; for(j=0;j<10;j++) if(a<b*(j+1)) break; a=a-b*j; } return a; } bool operator < (const Big_integer& b) const { if(len != b.len) return len<b.len; for(int i=len-1;i>=0;i--) if(d[i]!=b.d[i]) return d[i]<b.d[i]; return false; } string str()const { char s[maxn]={}; for(int i=0;i<len;i++) s[len-1-i]=d[i]+‘0‘; return s; } }; istream& operator >> (istream& in,Big_integer& x) { string s; in>>s; x=s.c_str(); return in; } ostream& operator << (ostream& out,const Big_integer& x) { out<<x.str(); return out; } } using namespace BigInteger; using namespace std; Big_integer a,b,k; int main() { //freopen("mul.in","r",stdin); //freopen("mul.out","w",stdout); cin>>a>>b>>k; cout<<a*b%k; //fclose(stdin); //fclose(stdout); return 0; }高精
T2 期望得分:30;實際得分:0 qwq
求和
【題目描述】
給定n個正整數d1 , d2 , d3 ..... dn。如果取出其中的任意兩個數(可以相同) ,則可以得到這兩個數的和。對於n個數,則至多可以產生n*(n + 1) / 2 種不同的和。
給出正整數 m,你需要判斷: 是否存在兩個整數 u, v , 滿足 du + dv = m.
【輸入文件】
輸入文件為 sum. in。
本題一個輸入中包含多組數據。 輸入第一行為一個整數 T , 表示數據組數。對於每組數據, 輸入的第一行為兩個正整數 n, m,輸入的第二行為 n 個正整數 d1, d2, d3 ..... dn
【輸出文件】
輸入文件為 sum.out。
輸出 T 行, 每行一個整數。 如果正整數 u, v 存在, 則輸出 1; 否則輸出 0。
【輸入輸出樣例】
sum.in | sum.out |
2 3 3 2 3 4 3 4 1 2 4 |
0 1 |
【數據規模和約定】
對於30%的數據,滿足 n <= 1000, m <= 10000;
對於60%的數據,滿足 n <= 105;
對於另30%的數據,滿足 m <= 107;
對於100%的數據,滿足 1 <= n <= 106, 1 <= di <= 109, 1 <= T <= 20.
【一些提示】
在下發文件中附有文件 sample.cpp, 包含了自定義函數 read()及其使用示例。 對於本題,請務必使用 read()函數進行讀入, 否則可能會有時間的問題。
思路: 30 分: 暴力
60 分: 排序後, 兩根指針進行掃?。
另 30 分: 用計數數組記錄數的分布
100 分: 在使用計數數組的基礎上進行拓展。考慮設置一個數 b ,把每個di 寫成 di = ai * b + ri ;並且把每個 di 按 ai 的值分成若幹組,ai 相同的數放在一組裏。
考慮一次性處理某一組的數。 如果假設 du + dv = m 的一個數在某一組中,那麽另一個數的分布範圍一定不超過兩組。 所以, 如果要檢測某一組的數是否可以作為一個加數, 只需要把另外的兩組放入計數數組即可。 這樣就解決了計數數組開不下的問題。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #include<cmath> #include<vector> using namespace std; typedef long long ll; typedef vector<int>::iterator iter; const int N = 1000010, M = 100000; int d[N]; int a[M]; vector<int> block[M]; int cnt[M * 4]; int read() { int x=0;char ch=getchar(); while(ch<‘0‘||ch>‘9‘) ch=getchar(); while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} return x; } int main() { freopen("sum.in","r",stdin); freopen("sum.out","w",stdout); setvbuf(stdin, new char[1 << 20], _IOFBF, 1 << 20); setvbuf(stdout, new char[1 << 20], _IOFBF, 1 << 20); int T = read(); while (T--) { int n = read(), m = read(); int maxblock = m / M; int ans = 0; for (int i = 0; i <= maxblock; i++) block[i].clear(); int tmptme = clock(); while (n--) { int x = read(); int y = x % M; x /= M; block[x].push_back(y); } for (int i = 0; i <= maxblock; i++) { int lblock = (m - (i + 1) * M + 1) / M; int rblock = (m - i * M) / M; int base = lblock * M; for (int j = lblock; j <= rblock; j++) { for (iter it = block[j].begin(); it != block[j].end(); it++) { cnt[*it + j * M - base] = 1; } } for (iter it = block[i].begin(); it != block[i].end(); it++) { if (cnt[m - i * M - *it - base]) { ans = 1; break; } } for (int j = lblock; j <= rblock; j++) { for (iter it = block[j].begin(); it != block[j].end(); it++) { cnt[*it + j * M - base] = 0; } } if (ans) break; } cout << ans << endl; } return 0; }標程
T3 期望得分:40;實際得分:40;
計數
【問題描述】
楊輝三角是一個滿足如下條件的三角形矩陣:
邊界條件:f [ i ] [ 0 ] = f [ i ] [ i ] = 1 , i >= 0 .
其余部分:f [ i ] [ j ] = f [ i - 1 ] [ j - 1 ] + f [ i - 1 ] [ j ] , 如果( i, j )不在邊界上
由此可以得出楊輝三角的前5行大致如下:
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
現在,給定正整數n你需要計算楊輝三角前n行有多少個偶數
【輸入文件】
輸入文件為 count.in。
輸入文件為一行一個正整數n。
【輸出文件】
輸入文件為 cs.out。
輸出一行一個整數, 為楊輝三角前n行的偶數個數。
【輸入輸出樣例】
5 4
【數據規模和約定】
對於40%的數據,滿足n<=1000。
對於70%的數據,滿足n<=106。
對於90%的數據,滿足n<=109。
對於100%的數據,滿足n<=10100。
思路:楊輝三角的奇偶分布是一個經典的分形圖形。 由此可以觀察出的規律有:楊輝三角的前 2n 行的奇數個數是 3n 個,如果找到一個 k,使 2k <= n < 2k-1, 那麽前 2k 行的奇數個數可以單獨計算; 而余下部分兩邊對稱, 所以可以遞歸算其中的一邊, 再乘以 2 加入答案。
上述算法計算出的是楊輝三角前 n 行有多少個奇數, 作差即可得到偶數的個數。
對於最後一個測試點, 需要使用高精度來支持上述做法。
#include<algorithm> #include<cstdio> using namespace std; int n, sum; int a[1000][1000]; int main() { //freopen("count.in","r",stdin); //freopen("count.out","w",stdout); scanf("%d", &n); a[0][0] = 1; for(int i = 0; i < n; i++) for(int j = 0; j < i+1; j++) { if(i == 0) a[i][j] = 1; else a[i][j] = a[i-1][j-1]+a[i-1][j]; if(a[i][j]%2 == 0) sum++; } printf("%d", sum); //fclose(stdin); fclose(stdout); return 0; }40分暴力
#include<iostream> using namespace std; long long n; long long work(long long n) { if(n==0 || n==1 )return 0; if(n&1)return 2*work(n/2)+work(n/2+1)+(n/2)*(n/2+1)/2; else return 3*work(n/2)+(n/2)*(n/2-1)/2; } int main() { //freopen("count.in","r",stdin); //freopen("count.out","w",stdout); cin>>n; cout<<work(n); //fclose(stdin);fclose(stdout); return 0; }90分遞歸 沒有高精
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #include<cmath> #include<string> using namespace std; const int N = 201; struct bignum { int a[N]; int n; bignum() { n = 0; memset(a, 0, sizeof(a)); } bignum(string s) { memset(a, 0, sizeof(a)); n = s.size(); for (int i = 0; i < n; i++) a[i] = s[n - 1 - i] -‘0‘; } bignum(int x) { memset(a, 0, sizeof(a)); n = 0; while (x) { a[n] = x % 10; x /= 10; n++; } } void deal() { for (int i = 0; i < n; i++) { if (a[i] < 0) { int tmp = (-a[i] - 1) / 10 + 1; a[i] += 10 * tmp; a[i + 1] -= tmp; } if (a[i] >= 10) { int tmp = a[i] / 10; a[i] -= 10 * tmp; a[i + 1] += tmp; if (i == n - 1 && a[i + 1] > 0) n++; } } while (n > 0 && a[n - 1] == 0) n--; } void div2() { int tmp = 0; for (int i = n - 1; i >= 0; i--) { int tmp_ = a[i] & 1; a[i] = (a[i] + tmp * 10) >> 1; tmp = tmp_; } deal(); } void print() { for (int i = n - 1; i >= 0; i--) cout << a[i]; cout << endl; } }; bignum operator + (const bignum &a, const bignum &b) { bignum c; c.n = max(a.n, b.n); for (int i = 0; i < c.n; i++) c.a[i] = a.a[i] + b.a[i]; c.deal(); return c; } bignum operator - (const bignum &a, const bignum &b) { bignum c; c.n = max(a.n, b.n); for (int i = 0; i < c.n; i++) c.a[i] = a.a[i] - b.a[i]; c.deal(); return c; } bignum operator * (const bignum &a, const bignum &b) { bignum c; c.n = a.n + b.n - 1; for (int i = 0; i < a.n; i++) for (int j = 0; j < b.n; j++) c.a[i + j] += a.a[i] * b.a[j]; c.deal(); return c; } bool no_bigger_than(const bignum &a, const bignum &b) { if (a.n < b.n) return 1; if (b.n < a.n) return 0; for (int i = a.n - 1; i >= 0; i--) { if (a.a[i] > b.a[i]) return 0; if (a.a[i] < b.a[i]) return 1; } return 1; } bignum calc(bignum n) { if (n.n == 0) return 0; bignum ret(1); bignum now(1); bignum big2(2); bignum big3(3); while (no_bigger_than(now * big2, n)) { now = now * big2; ret = ret * big3; } /* cout << "*****" << endl; n.print(); now.print(); ret.print(); cout << "*****" << endl; */ return ret + big2 * calc(n - now); } int main() { freopen("count.in","r",stdin); freopen("count.out","w",stdout); string s; cin >> s; bignum a(s); bignum n(s); bignum b(1); //b.print(); bignum c = a + b; //a.print(); //c.print(); //return 0; a = a * c; //a.print(); a.div2(); //a.print(); (a - calc(n)).print(); return 0; }標程
附加題:HDU 矩形面積並
記2018/4/29 qbxt 測試