(抖)
A: One
约瑟夫问题
考试的时候没想出来 (wtcl)
30pts: 直接大力模拟 用vis标记人是否死过 如果死过就不报数了
60pts: STL vector可以直接碾过去
考虑为什么30pts会慢 因为vis跳的时候很多没用的操作
可以用pos链表记录一下该跳到哪个人 可以省去遍历死去人的时间
正解是推柿子 其实之前讲过了类似解法但是并没有想出来
大概是每次从0开始编号 然后柿子推一推就好了 主要思想是求出当前活着的人在上一轮的编号 然后递推就完了
#include<bits/stdc++.h>
using namespace std;
int main(){
freopen("one.in","r",stdin);
freopen("one.out","w",stdout);
int T;scanf("%d",&T);
while(T--) {
int n;scanf("%d",&n);
int nw = 0;
for(int i = 2;i <= n;++i) nw = (nw - i + 1 + n) % i;
cout << nw + 1 << endl;
}
return 0;
}
B:哪一天她能重回我身边
纯模拟
记录几种情况随便打打
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1000;
const int now = maxn;
char s[maxn];
int cnt[maxn << 1][maxn << 1];
int k;
int main(){
freopen("block.in","r",stdin);
freopen("block.out","w",stdout);
int T;scanf("%d",&T);
while(T--) {
memset(cnt,0,sizeof(cnt));
scanf("%d",&k); scanf("%s",s + 1);
int len = strlen(s + 1);
if(k == 1) {
int x = 0,y = 0;
cnt[x + now][y + now]++;
int Max = 1;
for(int i = 1;i <= len;++i) {
if(s[i] == 'N') y++;
if(s[i] == 'S') y--;
if(s[i] == 'E') x++;
if(s[i] == 'W') x--;
++cnt[x + now][y + now];
if(cnt[x + now][y + now] > Max) Max = cnt[x + now][y + now];
}
printf("%d
%d
%d
",x,y,Max);
}
else {
int cur = 1;
int x = 0,y = 0;
cnt[x + now][y + now]++;
int Max = 1;
for(int i = 1;i <= len;++i) {
if(cur == 1) {
if(s[i] == 'N') {
y++;
for(int j = y;j <= y + k - 1;++j) {
cnt[x + now][j + now]++;
if(cnt[x + now][j + now] > Max) Max = cnt[x + now][j + now];
}
cur = 2;
}
if(s[i] == 'S') {
y -= k;
for(int j = y;j <= y + k - 1;++j) {
cnt[x + now][j + now]++;
if(cnt[x + now][j + now] > Max) Max = cnt[x + now][j + now];
}
cur = 2;
}
if(s[i] == 'E') {
x++;
for(int j = x;j <= x + k - 1;++j) {
cnt[j + now][y + now]++;
if(cnt[j + now][y + now] > Max) Max = cnt[j + now][y + now];
}
cur = 3;
}
if(s[i] == 'W') {
x -= k;
for(int j = x;j <= x + k - 1;++j) {
cnt[j + now][y + now]++;
if(cnt[j + now][y + now] > Max) Max = cnt[j + now][y + now];
}
cur = 3;
}
//cout << cur << endl;
continue;
}
if(cur == 2) {
if(s[i] == 'N') {
y += k;
cnt[x + now][y + now]++;
if(cnt[x + now][y + now] > Max) Max = cnt[x + now][y + now];
cur = 1;
}
if(s[i] == 'S') {
y--;
cnt[x + now][y + now]++;
if(cnt[x + now][y + now] > Max) Max = cnt[x + now][y + now];
cur = 1;
}
if(s[i] == 'E') {
x++;
for(int j = y;j <= y + k - 1;++j) {
cnt[x + now][j + now]++;
if(cnt[x + now][j + now] > Max) Max = cnt[x + now][j + now];
}
cur = 2;
}
if(s[i] == 'W') {
x--;
for(int j = y;j <= y + k - 1;++j) {
cnt[x + now][j + now]++;
if(cnt[x + now][j + now] > Max) Max = cnt[x + now][j + now];
}
cur = 2;
}
//cout << cur << endl;
continue;
}
if(cur == 3) {
if(s[i] == 'N') {
y++;
for(int j = x;j <= x + k - 1;++j) {
cnt[j + now][y + now]++;
if(cnt[j + now][y + now] > Max) Max = cnt[j + now][y + now];
}
cur = 3;
}
if(s[i] == 'S') {
y--;
for(int j = x;j <= x + k - 1;++j) {
cnt[j + now][y + now]++;
if(cnt[j + now][y + now] > Max) Max = cnt[j + now][y + now];
}
cur = 3;
}
if(s[i] == 'E') {
x += k;
cnt[x + now][y + now]++;
if(cnt[x + now][y + now] > Max) Max = cnt[x + now][y + now];
cur = 1;
}
if(s[i] == 'W') {
x--;
cnt[x + now][y + now]++;
if(cnt[x + now][y + now] > Max) Max = cnt[x + now][y + now];
cur = 1;
}
//cout << cur << endl;
continue;
}
}
if(cur == 1) {
printf("%d
%d
%d
",x,y,Max);
}
if(cur == 2) {
for(int i = 1;i <= k;++i) printf("%d ",x);
printf("
");
for(int i = y;i <= y + k - 1;++i) printf("%d ",i);
printf("
%d
",Max);
}
if(cur == 3) {
for(int i = x;i <= x + k - 1;++i) printf("%d ",i);
printf("
");
for(int i = 1;i <= k;++i) printf("%d ",y);
printf("
%d
",Max);
}
}
}
return 0;
}
C: 数字
然而似乎并不会
害怕.jpg
D: 甜圈
两种解题方法
正解 : 对操作哈希 然后求有多少个叶子节点的值等于我们要求的值就好了 对于每次区间一次操作 就是一次区间乘带一次区间加 最后把所有lazy 都pushdown下去统计答案
另一种思路: 可以保存当前区间进行过哪些次操作 l 和 r表示时间最早和最晚的操作是什么 对于一个区间 如果不合法就让l 和 r都等于-1 如果并没有进行过任何操作就是0
对于0的状态显然一定合法 然后如果对于区间进行了一次修改 那就保留一个lazy 标记 然后如果可以和子区间中的r进行合并就让它合并 最后大力pushdown 然后统计答案
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int maxn = 2e5 + 10;
const ull base = 233;
int ans = 0;
ull t[maxn << 2];
ull add[maxn << 2]; //加法标记
ull mul[maxn << 2];
void pushdown(int rt,int l,int r){
int mid = l + r >> 1;
t[rt << 1] = t[rt << 1] * mul[rt] + add[rt] * (mid - l + 1);
t[rt << 1 | 1] = t[rt << 1 | 1] * mul[rt] + add[rt] * (r - mid);
add[rt << 1] = add[rt << 1] * mul[rt] + add[rt];
add[rt << 1 | 1] = add[rt << 1 | 1] * mul[rt] + add[rt];
mul[rt << 1] *= mul[rt];
mul[rt << 1 | 1] *= mul[rt];
mul[rt] = 1; add[rt] = 0;
}
void modify(int rt,int l,int r,int L,int R,int k){
if(L <= l && R >= r) return t[rt] += k * (r - l + 1),add[rt] += k,void();
int mid = l + r >> 1;
pushdown(rt,l,r);
if(L <= mid) modify(rt << 1,l,mid,L,R,k);
if(R > mid) modify(rt << 1 | 1,mid + 1,r,L,R,k);
t[rt] = t[rt << 1] + t[rt << 1 | 1];
}
void mult(int rt,int l,int r,int L,int R,int k){
if(L <= l && R >= r) return add[rt] *= k,mul[rt] *= k,t[rt] *= k,void();
int mid = l + r >> 1;
pushdown(rt,l,r);
if(L <= mid) mult(rt << 1,l,mid,L,R,k);
if(R > mid) mult(rt << 1 | 1,mid + 1,r,L,R,k);
t[rt] = t[rt << 1] + t[rt << 1 | 1];
}
int ask(int rt,int l,int r,int L,int R){
if(L <= l && R >= r) return t[rt];
int mid = l + r >> 1;
pushdown(rt,l,r);
if(R <= mid) return ask(rt << 1,l,mid,L,R);
if(L > mid) return ask(rt << 1 | 1,mid + 1,r,L,R);
return ask(rt << 1,l,mid,L,R) + ask(rt << 1 | 1,mid + 1,r,L,R);
}
int main(){
freopen("deco.in","r",stdin);
freopen("deco.out","w",stdout);
int n,K,T;scanf("%d%d%d",&n,&K,&T);
memset(mul,1,sizeof(mul));
for(int i = 1;i <= T;++i) {
int l,r,x;scanf("%d%d%d",&l,&r,&x);
mult(1,1,n,l,r,base);
modify(1,1,n,l,r,x);
}
int T_T = 0;
for(int i = 1;i <= K;++i) T_T = T_T * base + i;
for(int i = 1;i <= n;++i) if(ask(1,1,n,i,i) == T_T) ans++;
cout << ans << endl;
return 0;
}