指望得分:\(100 + 80 + 10 = 190\)
實際得分:\(90 + 80 + 10 = 180\)ios
這是在清北的第一場考試,也是在清北考的最高的一次了吧。。原本覺得能拿\(190\)的,沒想到強者太多,\(AK\)的一羣,\(200\)分大衆分。。我好菜git
\(T1\)是個簡單題,卻由於\(1-1=0\)這個點忘記去除前導零而失去了\(10\)分,之後要多對拍,多注意細節數據結構
#include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int N = 1e5 + 11; inline int read() { char c = getchar(); int x = 0, f = 1; for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1; for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48); return x * f; } char s[N]; string a; int len, now, whe, pos; int main() { scanf("%s", s + 1); len = strlen(s + 1), now = s[1] - '0', whe = 1, pos = 1; for(int i = 2, x; i <= len; i++) { x = s[i] - '0'; if(x > now) { now = x; whe = i; pos = i; } else if(x == now) pos = i; if(x < now) break; } if(whe == len || pos == len) return cout << (s + 1) << '\n', 0; for(int i = 1; i < whe; i++) a += s[i]; if(s[whe] - 1 != '0') a += s[whe] - 1; for(int i = whe + 1; i <= len; i++) a += '9'; cout << a; return 0; }
看式子不懂,以後手算一下發現就是個逆序對,進而發現能夠轉化爲求哪些區間包含這對逆序對,而後這對逆序對的值乘以區間個數,式子以下ui
\[\sum_j a_j * (n - j + 1) *\sum_{a_i > a_j, i < j} a_i * i\]spa
後面的能夠用數據結構維護,發現模數是\(1e12+7\),兩個\(10^12\)的數相乘會爆\(long\ long\),因此要用快速乘code
而後就作完了get
#include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define lowbit(x) (x & -x) #define int long long using namespace std; const int N = 5e5 + 11; const int mod = 1e12 + 7; inline int read() { char c = getchar(); int x = 0, f = 1; for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1; for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48); return x * f; } int n; int a[N], ans = 0; int b[N], p[N], f[N]; inline int mul(int a, int b, int res = 0) { while(b) { if(b & 1) ans = (ans + a) % mod; a = a + a % mod; b >>= 1; } return res; } inline int query(int x) { int ans = 0; for(int i = x; i; i -= lowbit(i)) ans = (ans + p[i]) % mod; return ans; } const int MAX = 1e5; inline void add(int x, int val) { for(int i = x; i <= MAX; i += lowbit(i)) p[i] = (p[i] + val) % mod; return; } signed main() { n = read(); for(int i = 1; i <= n; i++) b[i] = a[i] = read(); sort(b + 1, b + 1 + n); for(int i = 1; i <= n; i++) f[i] = lower_bound(b + 1, b + 1 + n, a[i]) - b; for(int i = 1; i <= n; i++) { int now = query(n) - query(f[i]); now = (now % mod + mod) % mod; ans = ans + mul(now * (n - i + 1), a[i]); ans = (ans % mod + mod) % mod; add(f[i], a[i] * i); } ans = (ans % mod + mod) % mod; cout << ans << '\n'; return 0; }
直接用線段樹掃描線就\(over\)了string
還有一種神奇作法。。it
#include <map> #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define max(a, b) (a > b ? a : b) #define min(a, b) (a < b ? a : b) #define PII pair<int, int> #define mk(x, y) make_pair(x, y) using namespace std; const int N = 5e4 + 11; const int M = 1e6 + 11; const int mod = 1e9 + 7; const int INF = 0x3f3f3f3f; inline int read() { char c = getchar(); int x = 0, f = 1; for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1; for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48); return x * f; } int n, m, a[N], b[N], c[N], d[N]; int mina, minb, maxc, maxd; map<pair<int, int>, int> mp; int main() { int T = read(); while(T--) { n = read(); mina = minb = INF; maxc = maxd = -INF; mp.clear(); for(int i = 1; i <= n; i++) { a[i] = read(), b[i] = read(), c[i] = read(), d[i] = read(); mina = min(mina, a[i]); minb = min(minb, b[i]); maxc = max(maxc, c[i]); maxd = max(maxd, d[i]); mp[mk(a[i], b[i])]++; mp[mk(a[i], d[i])]++; mp[mk(c[i], b[i])]++; mp[mk(c[i], d[i])]++; } int cnt = 0; if(mp[mk(mina, minb)] == 1) cnt++; if(mp[mk(mina, maxd)] == 1) cnt++; if(mp[mk(maxc, minb)] == 1) cnt++; if(mp[mk(maxc, maxd)] == 1) cnt++; if(cnt != 4) { puts("Guguwansui"); continue; } cnt = 0; for(int i = 1; i <= n; i++) { if(mp[mk(a[i], b[i])] == 1) cnt++; if(mp[mk(a[i], d[i])] == 1) cnt++; if(mp[mk(c[i], b[i])] == 1) cnt++; if(mp[mk(c[i], d[i])] == 1) cnt++; } if(cnt == 4) puts("Perfect"); else puts("Guguwansui"); } return 0; } //這題太神了我不會。