A. R
鏈接:https://ac.nowcoder.com/acm/contest/23479/A
來源:牛客網
題目描述
小紅拿到了一個長度為 nn 的字符串,該字符串僅由大寫字母組成。
小紅很喜歡紅色(用'R'字母表示),但她非常討厭紫色(用'P'字母表示)。
她想取一個連續子串,該子串包含至少 kk 個'R'字符,且不能包含'P'字符。
你能告訴她有多少合法的方案可以取到嗎?
注:只要連續子串的起始位置或終止位置不同,我們就認為是兩個不同的方案。
輸入描述:
第一行輸入兩個正整數 nn 和 kk ,用空格隔開。
輸入一行字符串,該字符串保證僅包含大寫字母('A'到'Z')。
數據范圍:
1≤n≤2000001≤n≤200000
1≤k≤201≤k≤20
輸出描述:
取一個連續子串,包含至少 k 個'R'字符、且不包含'P'字符的方案數。
示例1
輸入
復制
13 3
RRRPBRRRDBRPR
輸出
復制
10
說明
共有 10 個合法的子串選擇方式。假設下標是從 0 到 12 ,那么 10 個合法串分別是:
s[0,2]s[0,2] = "RRR"
s[4,7]s[4,7] = "BRRR"
s[4,8]s[4,8] = "BRRRD"
s[4,9]s[4,9] = "BRRRDB"
s[4,10]s[4,10] = "BRRRDBR"
s[5,7]s[5,7] = "RRR"
s[5,8]s[5,8] = "RRRD"
s[5,9]s[5,9] = "RRRDB"
s[5,10]s[5,10] = "RRRDBR"
s[6,10]s[6,10] = "RRDBR"這些串均含有不小於 3 個字符 'R',且不包含字符 'P'
和前面一場一個題很像,首先處理出所有不包含P的區間,然后枚舉右端點,二分找滿足條件的最靠右的左端點(可以證明答案具有單調性)然后剩下部分都可以作為左端點,計算貢獻即可。
#include <bits/stdc++.h>
#define fi first
#define se second
using namespace std;
#define ll long long
int n, k;
char s[200006];
int sum[200005] = { 0 };
vector<pair<int, int> > v;
int main() {
cin >> n >> k;
scanf("%s", s + 1);
int lst = 0;
s[n + 1] = 'P';
for(int i = 1; i <= n + 1; i++) {
if(s[i] == 'P') {
if(lst + 1 <= i - 1 && i - 1 - lst - 1 + 1 >= k) v.push_back(make_pair(lst + 1, i - 1));
lst = i;
}
}
long long ans = 0;
for(int i = 1; i <= n; i++) {
sum[i] = sum[i - 1];
if(s[i] == 'R') sum[i]++;
}
for(auto x : v) {
int L = x.fi, R = x.se;
for(int i = L; i <= R; i++) {
int l = 1, r = i - L + 1, mid;
while(l < r) {
mid = (l + r) >> 1;
if(sum[i] - sum[i - mid] >= k) {//注意要取等
r = mid;
} else l = mid + 1;
}
if(sum[i] - sum[i - l] == k) {
ans += 1ll * (i - l + 1) - L + 1;
}
}
}
cout << ans;
return 0;
}
B. 進制
鏈接:https://ac.nowcoder.com/acm/contest/23479/B
來源:牛客網
題目描述
小紅拿到了一個長度為 nn 的數字串 ss(只有 '0' ~ '9' 這十種字符),她有 qq 次以下兩種操作:
第一種: 輸入1 x y,修改第 x 個字符為 y ,即令sx=ysx=y
第二種: 輸出 2 x y ,代表查詢區間 [x,y],該區間子串所能表示的某進制的最小值(進制必須合法,且必須是二進制到十進制之間,可以包含前導零),對 1000000007 取模。
例如若查詢的子串為 "47",其能表示的最小值是八進制代表的"47",其數值為39,因此輸出39。如果用十進制表示,則數值47,比39大。 例如若查詢的子串為 "10000",其能表示的最小值是二進制代表的"10000",其數值為16,因此輸出16。
輸入描述:
第一行輸入兩個正整數 nn 和 qq ,用空格隔開。分別代表初始字符串和操作次數。
第二行輸入一個長度為 nn的字符串 ss。
接下來的 qq 行,每行輸入 3 個整數 op x yop x y,代表一次操作。
數據范圍:
1≤n,q≤1051≤n,q≤105
opop 為 1 或者 2 。
若 opop 為 1,那么1≤x≤n1≤x≤n , 0≤y≤90≤y≤9
若 opop 為 2,那么1≤x≤y≤n1≤x≤y≤n
輸出描述:
對於每次 op=2op=2 的操作,輸出該子串查詢的合法進制最小值。由於該數過大,請對 1000000007 取模。
看到單點修改區間查詢很容易想到線段樹。可以在線段樹的每個節點上維護2到10進制的這一段的和。注意,對於每個進制p,每個位置i的值x並非這個數本身,而是\(x\times p^{n - i}\),即對於原串而言是從右到左由低到高。例如對於串12321,以4進制為例,第一個位置的值是81,第二個位置的值是54,那么[1, 2]的區間和是81+54=135。同時還要維護區間的對於每個位置數字的最值,比如對於串12321,[1, 4]的最值為3。這樣對於每個詢問,先找到區間的最值mx,mx+1就是需要使用的進制,這時再查詢區間的對應這個進制的和。因為查詢區間右端點r不一定等於n,因此還需要除以\(base^{n - r}\),由於是在模意義下的除法,需要用到逆元。還需要注意,可能有這樣的問題,例如對於串4567,如果是在2、3進制下實際上是沒有意義的,因此對於a[pos] >= base的位置pos直接以0代替值即可。具體細節見代碼。
#include <bits/stdc++.h>
#define mod 1000000007
#define pb push_back
#define ll long long
#define int long long
#define fi first
#define se second
using namespace std;
int n, q;
long long a[100006];
char s[100005];
struct SegmentTree {
int l, r;
long long dat[11];
long long mx;
} t[100005 * 4];
ll fpow(ll a, ll b) {
ll ans = 1;
for(; b; b >>= 1) {
if(b & 1) ans = ans * a % mod;
a = a * a % mod;
}
return ans;
}
void build(int p, int l, int r) {
t[p].l = l, t[p].r = r;
if(l == r) {
t[p].mx = a[l];
for(int i = 2; i <= 10; i++) {
if(i > a[l]) t[p].dat[i] = a[l] * fpow(1ll * i, n - l) % mod;//從右到左由低到高
else t[p].dat[i] = 0ll;
}
return;
}
int mid = (l + r) >> 1;
build(2 * p, l, mid);
build(2 * p + 1, mid + 1, r);
t[p].mx = max(t[2 * p].mx, t[2 * p + 1].mx);
for(int i = 2; i <= 10; i++) {
t[p].dat[i] = (t[2 * p].dat[i] + t[2 * p + 1].dat[i]) % mod;
}
}
ll ask_mx(int p, int l, int r, int L, int R) {
if(t[p].l >= L && t[p].r <= R) {
return t[p].mx;
}
int mid = (l + r) >> 1;
ll ans = -1;
if(L <= mid) ans = ask_mx(2 * p, l, mid, L, R);
if(R > mid) ans = max(ans, ask_mx(2 * p + 1, mid + 1, r, L, R));
return ans;
}
void modify(int p, int l, int r, int pos, ll x) {
if(t[p].l == t[p].r) {
t[p].mx = x;
a[l] = x;
for(int i = 2; i <= 10; i++) {
if(i > a[l]) t[p].dat[i] = a[l] * fpow(1ll * i, n - l) % mod;//從右到左由低到高
else t[p].dat[i] = 0ll;
}
return;
}
int mid = (l + r) >> 1;
if(pos <= mid) modify(2 * p, l, mid, pos, x);
else modify(2 * p + 1, mid + 1, r, pos, x);
t[p].mx = max(t[2 * p].mx, t[2 * p + 1].mx);
for(int i = 2; i <= 10; i++) {
t[p].dat[i] = (t[2 * p].dat[i] + t[2 * p + 1].dat[i]) % mod;
}
}
ll ask_sum(int id, int p, int l, int r, int L, int R) {
if(t[p].l >= L && t[p].r <= R) {
return t[p].dat[id];
}
int mid = (l + r) >> 1;
ll ans = 0;
if(L <= mid) ans = ask_sum(id, 2 * p, l, mid, L, R);
if(R > mid) ans = (ans + ask_sum(id, 2 * p + 1, mid + 1, r, L, R)) % mod;
return ans;
}
signed main() {
cin >> n >> q;
scanf("%s", s + 1);
for(int i = 1; i <= n; i++) {
a[i] = s[i] - '0';
}
build(1, 1, n);
while(q--) {
int op;
ll x, y;
scanf("%d%lld%lld", &op, &x, &y);
if(op == 1) {
modify(1, 1, n, x, y);
} else {
ll mx = ask_mx(1, 1, n, x, y);
//cout << mx << endl;
mx++;
ll ans = ask_sum(mx, 1, 1, n, x, y);
//ans /= mx **
ans = ans * fpow(fpow(mx, n - y), mod - 2) % mod;
printf("%lld\n", ans);
}
}
}
C. 藍彗星
鏈接:https://ac.nowcoder.com/acm/contest/23479/C
來源:牛客網
題目描述
你相信天上會出現藍色的彗星嗎?
小紅是一個天文學愛好者。她最喜歡的業余活動就是天體觀測。
這天夜里,星漢燦爛。小紅拉上了小夢前往了教學樓的天台,組裝好了天文望遠鏡。
根據預測,有兩種不同顏色的彗星:紅彗星和藍彗星。每顆彗星會在某一時間段出現 tt 秒然后消失。
小紅想知道,自己總共有多少秒,能看到藍彗星且看不到紅彗星?
ps:不用考慮晝夜更替等真實場景。我們假設小紅所在的為架空世界,夜晚有無限長。
輸入描述:
第一行輸入兩個正整數 nn 和 tt ,用空格隔開。分別代表彗星的數量、每個彗星的持續時間。
第二行輸入一個長度為 nn 的,只有兩種字符'B'和'R'組成的字符串。用來表示每顆彗星的顏色。字符'B'代表藍色,字符'R'代表紅色。
第三行輸入 nn 個正整數 aiai ,代表每顆彗星的開始時刻。
數據范圍:
1≤n,t,ai≤1000001≤n,t,ai≤100000
輸出描述:
能看到藍彗星且看不到紅彗星的總秒數。
區間覆蓋判斷,使用差分維護即可。
#include <bits/stdc++.h>
#define fi first
#define se second
using namespace std;
#define ll long long
int n, t, a[100005];
string s;
int d1[200005], d2[200005];
int main() {
cin >> n >> t;
cin >> s;
s = " " + s;
for(int i = 1; i <= n; i++) {
cin >> a[i];
}
memset(d1, 0, sizeof(d1));
memset(d2, 0, sizeof(d2));
for(int i = 1; i <= n; i++) {
if(s[i] == 'B') {
d1[a[i]]++;
d1[a[i] + t]--;
} else {
d2[a[i]]++;
d2[a[i] + t]--;
}
}
int ans = 0;
for(int i = 1; i <= 200003; i++) {
d1[i] += d1[i - 1];
d2[i] += d2[i - 1];
//cout << i << " " << d1[i] << " " << d2[i] << endl;
if(d1[i] && d2[i] == 0) ans++;
}
cout << ans;
}
D. 雪色光暈
鏈接:https://ac.nowcoder.com/acm/contest/23479/D
來源:牛客網
題目描述
今年的雪來得格外的早。雪把大地染成一片橙色。
小紅正在雪地中奔跑。雪地可以看成是一個二維平面,小紅的初始坐標是 (x0,y0)(x0,y0),她每秒有個方向向量 (xi,yi)(xi,yi),會沿着該方向直線奔跑1秒(例如,第一秒之后,小紅的坐標就變成了 (x0+x1,y0+y1)(x0+x1,y0+y1)。小果站在坐標 (x,y)(x,y)處原地不動。小紅想知道,在跑步過程中,自己和小果的最短距離是多少?
輸入描述:
第一行是一個正整數 nn ,代表小紅奔跑的總時間。
第二行是四個整數 x0x0、 y0y0、xx 和 yy ,用空格隔開。用來表示小紅的初始坐標和小果的坐標。
接下來的nn行,每行輸入兩個整數 xixi 和 yiyi ,用來表示小紅每秒的方向向量坐標。
數據范圍:
1≤n≤2000001≤n≤200000
−109≤x,y,xi,yi≤109−109≤x,y,xi,yi≤109
輸出描述:
小紅離小果最近的距離。如果你的答案和正確答案的相對誤差不超過 10−710−7,則認為答案正確。
示例1
輸入
復制
1
1 1 1 2
2 0
輸出
復制
1.0
說明
小紅在初始的位置上和小果的距離最近,為1.0
示例2
輸入
復制
2
0 0 1 1
1 0
1 1
輸出
復制
0.70710678
說明
小紅和小果的初始距離是22
第一次從(0,0)到(1,0),最近的距離在(1,0)處取到,是1.0。
第二次從(1,0)到(2,1),最近的距離在(1.5,0.5)處取到,是22≈0.7071067822≈0.70710678
所以最小值是0.70710678
示例3
輸入
復制
1
-10 0 1 1
20 0
輸出
復制
1.0
實際上就是求n次點到線段的距離。直接抄kuangbin計算幾何板子就能過~
int main() {
ll n, x0, y0, x, y;
cin >> n;
cin >> x0 >> y0 >> x >> y;
double ans = 1e18;
ans = min(ans, f(x0, y0, x, y));
for(int i = 1; i <= n; i++) {
ll xi, yi;
cin >> xi >> yi;
Point a(x0, y0);
Point b(x0 + xi, y0 + yi);
Line line(a, b);
Point p(x, y);
ans = min(ans, line.dispointtoseg(p));
x0 += xi;
y0 += yi;
}
cout << fixed << setprecision(9) << ans;
}
E. 真假簽到題
鏈接:https://ac.nowcoder.com/acm/contest/23479/E
來源:牛客網
題目描述
作為對萌新《友好》的寒假集訓營,小紅當然要送給大家一道簽到題!
小紅拿到了一份代碼:
long long f(long long x){
if(x==1)return 1;
return f(x/2)+f(x/2+x%2);
}
給定一個正整數 xx ,她希望你能輸出 f(x)f(x) 的值,你能幫幫她么?
輸入描述:
一個正整數 xx 。
數據范圍: 1≤x≤10181≤x≤1018
輸出描述:
f(x)f(x) 的值。
示例1
輸入
復制
1
輸出
復制
1
說明
當 x=1x=1 時,函數將直接返回 1。
直接輸出x。剛睡醒以為手速題還wa了兩發,氣壞了
F. 小紅的記譜法
鏈接:https://ac.nowcoder.com/acm/contest/23479/F
來源:牛客網
題目描述
小紅很喜歡音樂。她發現簡譜有 2 種記譜的方法:
第一種是用 1234567 分別表示 do re me fa so la si
第二種是用 CDEFGAB 分別表示 do re me fa so la si
例如著名的《小星星》的表示方式,如果用第一種為 11556654433221 ,如果用第二種則是 CCGGAAGFFEEDDC 。
如果高了 8 度,那么對於第一種方式,可以采用在數字頭頂加個點來表示。本題為了表示方便,則在數字后面加上一個 '*' 表示該數字為高八度。
同理,后面加了 x 個 '*' 代表高了 x 個八度。例如 2** 代表比普通的 2(re) 高了 16 度。
如果低了 8 度,那么對於第一種方式,可以采用在數字腳下加個點來表示。本題為了表示方便,則在數字后面加上一個 '.' 表示該數字為低八度。
同理,后面加了 x 個 '.' 代表低了 x 個八度。例如 2.. 代表比普通的 2(re) 低了 16 度。
舉個例子,周傑倫的《夜曲》副歌部分的前兩句用第一種簡譜表示為:
6.7.11117.3366654511
而第二種記譜法和第一種不同的在於,尖括號’<‘代表后面所有的音比前面的音低 8 度。反尖括號'>'則代表后面所有的音比前面的音高 8 度。
例如,>>D 和第二種記譜法的 2** 是等價的,代表比 D 高了 16 度。
<<D 和第二種記譜法的 2.. 是等價的,代表比 D 低了 16 度。
那么《夜曲》的副歌部分的前兩句用第二種簡譜可以表示為:
<AB>CCCC<B>EEAAAGFGCC
再例如,《opara2》是vitas著名的高音之作。其中一個片段(副歌前到第一句副歌)用兩種記譜法分別可以表達如下:
3.7.6.127.127.13.7.6.1243236232323.32327.7.7.7.127.7*1**2**3**2**3**2**1**7*1**2**7*
<EBA>CD<B>CD<B>C<EBA>CDFEDEADEDED<E>EDED<BBBB>CD<B>>B>CDEDEDC<B>CD<B
轉到副歌第一句:”7.712323**…………“這里時,由於7比7.高了2個8度,所以后面要接兩個>,之后的1**到達了一個更高的音程,所以在B后面繼續接一個>。
因此這部分應該記為">B>CDEDE…………"
請注意,第二種記譜法並不是唯一的,例如:
11.1..
轉為第二種記譜法,可以記為:
C<C><<C>>
但也可以記為:
C<C<C
不過第一種記譜法一定是唯一表示的。
現在給出一段第二種記譜法的簡譜,小紅希望你能輸出對應的第一種記譜法。
輸入描述:
一行字符串, 為第二種記譜法的簡譜。
字符串長度不超過1000。
輸出描述:
一行字符串, 為第一種記譜法描述的簡譜
示例1
輸入
復制
<<<<<<<<ECA>>>>>>>>
輸出
復制
3........1........6........
說明
音調的音域(度)上不封頂, 下不封底。輸入中末尾的 '>' 也都是可以省略的,代表同一張譜的表示。
示例2
輸入
復制
G>GFEEFEEFEFEDC<
輸出
復制
55*4*3*3*4*3*3*4*3*4*3*2*1*
示例3
輸入
復制
<G>GDEC>C<GEC>C<G>EDGB>C
輸出
復制
5.52311*5311*53*2*5*7*1**
示例4
輸入
復制
<EBA>CD<B>CD<B>C<EBA>CDFEDEADEDED<E>EDED<BBBB>CD<B>>B>CDEDEDC<B>CD<B
輸出
復制
3.7.6.127.127.13.7.6.1243236232323.32327.7.7.7.127.7*1**2**3**2**3**2**1**7*1**2**7*
簡單模擬,難點在於讀懂又臭又長的題干~
#include <bits/stdc++.h>
#define fi first
#define se second
using namespace std;
#define ll long long
map<char, char> m;
int main() {
m['C'] = '1', m['D'] = '2', m['E'] = '3', m['F'] = '4', m['G'] = '5', m['A'] = '6', m['B'] = '7';
string s, ans = "";
cin >> s;
int base = 0;
for(int i = 0; i < s.size(); i++) {
if(s[i] == '>') {
base++;
} else if(s[i] == '<') {
base--;
} else {
ans += m[s[i]];
for(int i = 1; i <= abs(base); i++) {
if(base < 0) ans += '.';
else if(base > 0) ans += '*';
}
}
}
cout << ans;
}
G. 子序列權值乘積
鏈接:https://ac.nowcoder.com/acm/contest/23479/G
來源:牛客網
題目描述
小紅定義一個數組的權值為該數組的最大值乘以最小值。例如數組 [4,1,3] 的權值是 4*1=4。
小紅拿到了一個數組。她想知道,這個數組的所有 非空****子序列 的權值的乘積是多少?由於該數過大,請對1000000007取模。
子序列的定理:對於一個數組,刪除其中某些數之后(也可以不刪)得到的數組。子序列中的數的相對順序必須和原數組中的順序相同。
例如:數組 [1,3,2] 的非空子序列有 [1] [3] [2] [1,3] [1,2] [3,2] [1,3,2] 共7個。
輸入描述:
第一行輸入一個正整數 nn ,代表數組的長度。
第二行輸入 nn 個正整數 aiai ,代表小紅拿到的數組。
數據范圍:
1≤n≤2000001≤n≤200000
1≤ai≤1091≤ai≤109
輸出描述:
數組所有子序列的權值的乘積。答案對1000000007取模。
示例1
輸入
復制
2
2 3
輸出
復制
216
說明
對於子序列 [2,3] ,其權值為 3 * 2 = 6。
對於子序列 [2] ,其權值為 2 * 2 = 4。
對於子序列 [3] ,其權值為 3 * 3 = 9。
因此所有非空子序列的權值乘積為: 6 * 4 * 9 = 216
示例2
輸入
復制
4
4 1 4 3
輸出
復制
757784222
首先注意到選的是自序列,因此順序實際上沒有關系,可以先排個序,然后考慮每個數作為最大值和最小值對答案的貢獻。因為答案本身就是每個自序列最大值最小值之積的積,所以這里可以直接乘。
#include <bits/stdc++.h>
#define mod 1000000007
#define pb push_back
#define fi first
#define se second
using namespace std;
#define ll long long
#define int long long
int n, a[200005], o[200005];
int b[200005];
void add(int x, int y) {
for(; x <= 200000; x += (x & -x)) b[x] += y;
}
int ask(int x) {
int ans = 0;
for(; x; x -= (x & -x)) ans += b[x];
return ans;
}
int f[200005];
ll fpow(ll a, ll b) {
ll ans = 1;
for(; b; b >>= 1) {
if(b & 1) ans = ans * a % mod;
a = a * a % mod;
}
return ans;
}
signed main() {
cin >> n;
vector<int> v;
f[0] = 1;
for(int i = 1; i <= n; i++) {
cin >> a[i];
f[i] = (f[i - 1] * 2) % (mod - 1);
}
sort(a + 1, a + n + 1);
ll ans = 1;
for(int i = 1; i <= n; i++) {
ans = ans * fpow(a[i], f[i - 1] + f[n - i]) % mod;
}
cout << ans;
return 0;
}
H. 真真真真真簽到題
鏈接:https://ac.nowcoder.com/acm/contest/23479/H
來源:牛客網
題目描述
作為對萌新友好的寒假集訓營,小紅當然要送給大家一道簽到題!
小紅和紫被困在一個正方體的內部。紫先選擇了一個位置,然后小紅選擇一個位置。紫希望離小紅盡可能近,小紅希望離紫盡可能遠。兩人都會選擇最優策略。
已知她們最終的距離為 xx 。小紅想知道正方體的體積是多少?
輸入描述:
一個正整數 xx 。
數據范圍: 1≤x≤1001≤x≤100
輸出描述:
最終正方體的體積。如果你的答案和正解的相對誤差不超過 10−410−4,則認為你的答案正確。
示例1
輸入
復制
13
輸出
復制
3382.5027771
說明
紫先選擇站在正方體的中心,然后小紅站在正方體的一個角上。可以證明這樣一定是最優的。
初中幾何題。實際上樣例解釋已經說出答案了。。
#include <bits/stdc++.h>
using namespace std;
int main() {
double x;
cin >> x;
cout << fixed << setprecision(6) << pow(x * 2 / sqrt(3), 3);
}
I. 爆炸的符卡洋洋灑灑
鏈接:https://ac.nowcoder.com/acm/contest/23479/I
來源:牛客網
題目描述
小紅正在研究如何把符卡組合出盡可能大威力的組合魔法。
小紅共有 nn 種符卡可以選擇,每種符卡最多只能選擇一次,每個符卡的魔力消耗為 aiai,威力為 bibi。
如果將多個符卡進行組合,則可以發動一個組合魔法。組合魔法的魔力消耗為選擇的符卡的魔力消耗的總和,其威力為選擇的符卡的威力的總和。
小紅必須保證最終符卡的魔力消耗總和為 kk 的倍數,否則小紅將受到魔力反噬而發動魔法失敗。
小紅想知道,自己能發動的組合魔法最大的威力是多少?
輸入描述:
第一行輸入兩個正整數 nn 和 kk ,用空格隔開。
接下來的 nn 行,每行輸入兩個正整數 aiai 和 bibi,用空格隔開。
數據范圍:
1≤n,k≤10001≤n,k≤1000
1≤ai,bi≤1091≤ai,bi≤109
輸出描述:
如果小紅無論如何也組合不了能發動的魔法,則輸出-1。
否則輸出最大的威力值。
示例1
輸入
復制
2 3
1 2
2 1
輸出
復制
3
說明
兩個符卡都選上,融合出的魔法消耗為3,是3的倍數。威力是3。
示例2
輸入
復制
2 2
1 2
2 1
輸出
復制
1
說明
選擇第二個符卡,消耗為2,是2的倍數。威力是1。
示例3
輸入
復制
3 4
1 2
5 3
1 4
輸出
復制
-1
說明
顯然,無論如何都組合不出消耗為4的倍數的魔法。
dp,設dp[i, j]為使用前i個能湊出j的消耗值(模k意義下)的最大威力。模k以后就可以寫出n^2的dp了,轉移方程見代碼。注意發生轉移的條件是前一個狀態的威力不為0!同時不要忘記當前卡不選的話也要更新dp數組。
#include <bits/stdc++.h>
#define fi first
#define se second
using namespace std;
#define ll long long
ll n, k;
ll a[1005], b[1005];
ll dp[2005][2005];
int main() {
cin >> n >> k;
for(int i = 1; i <= n; i++) {
cin >> a[i] >> b[i];
a[i] %= k;
}
ll ans = 0;
for(ll i = 1; i <= n; i++) {
dp[i][a[i]] = b[i];
for(ll j = 0; j <= k - 1; j++) {
dp[i][j] = max(dp[i][j], dp[i - 1][j]);
if(dp[i - 1][(j - a[i] + k) % k])
dp[i][j] = max(dp[i][j], dp[i - 1][(j - a[i] + k) % k] + b[i]);
}
ans = max(ans, dp[i][0]);
}
if(ans) cout << ans;
else cout << -1;
return 0;
}
// 3 3
// 1 5
// 2 5
// 2 7
J. 區間合數的最小公倍數
鏈接:https://ac.nowcoder.com/acm/contest/23479/J
來源:牛客網
題目描述
小紅拿到了兩個正整數 ll 和 rr 。
她想知道 [l,r][l,r] 區間所有合數的最小公倍數是多少?由於答案可能過大,請對1000000007取模。
合數的定義:因子的個數不小於3的正整數。例如:9的因子有1、3、9這三個,所以9是合數。
輸入描述:
兩個正整數 ll 和 rr ,用空格隔開。
數據范圍:1≤l≤r≤300001≤l≤r≤30000
輸出描述:
若區間 [l,r][l,r] 中沒有任何合數,則輸出-1。
否則輸出區間 [l,r][l,r] 所有合數的最小公倍數,答案對1000000007取模。
示例1
輸入
復制
2 3
輸出
復制
-1
說明
區間 [2,3] 的兩個數 2 和 3 都是素數,不是合數。
示例2
輸入
復制
4 6
輸出
復制
12
說明
區間[4,6]中有三個數:4、5、6,其中 5 是素數, 4 和 6 是合數,它們的最小公倍數是12。
示例3
輸入
復制
25000 30000
輸出
復制
187554966
直接硬求也可以(注意除法換成逆元),或者用LCM的性質:https://www.cnblogs.com/lipoicyclic/p/14387217.html
#include <bits/stdc++.h>
#define ll long long
#define mod 1000000007
#define maxn 1e5
using namespace std;
long long x[10005], p[10005];
int n, sg[1000007], primes[1000007];
int cnt[1000007] = { 0 };
bool is[1000006] = { 0 };
int m=0;
void getprimes(){
sg[1]=0;
for(int i=2;i<=maxn;i++){
sg[i]=1;
}
for(int i=2;i<=maxn;i++){
if(sg[i]==1) {sg[i]=1;primes[++m]=i; is[i] = 1;}
for(int j=1;j<=m&&primes[j]*i<=maxn;j++){
sg[primes[j]*i]=sg[i]+1;
if(i%primes[j]==0)break;
}
}
}
ll fpow(ll a, ll b) {
ll ans = 1;
for(; b; b >>= 1) {
if(b & 1) ans = ans * a % mod;
a = a * a % mod;
}
return ans;
}
int main()
{
int l, r;
cin >> l >> r;
getprimes();
for(int i = l; i <= r; i++) {
if(is[i]) continue;
int tmp = i;
for(int j = 1; j <= m; j++) {
if(primes[j] > tmp) break;
if(tmp % primes[j] != 0) continue;
int tot = 0;
while(tmp % primes[j] == 0) tot++, tmp /= primes[j];
cnt[primes[j]] = max(tot, cnt[primes[j]]);
}
}
ll ans = 1;
for(int i = 1; i <= m; i++) {
ans = ans * fpow(primes[i], cnt[primes[i]]) % mod;
}
if(ans != 1) cout << ans;
else cout << -1;
return 0;
}
K. 小紅的真真假假簽到題題
二進制下整體右移相當於乘2,為了保證1的個數不相同,再加上x即可。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
int main() {
ll x;
cin >> x;
cout << (x << 32) + x;
return 0;
}