hoj暑期第四场
1001
- 题意
给你定义一个函数
然后,(S(x)=sum_{j=1}^xf(j)), 求 (lim limits_{x o infty}S(x)=c) , s(x)中x趋近正无穷的极限得是个常数
- 思路
非常难受,就这种题,还有人能wa4,5发的啊。
呜呜呜呜呜
code:
void solve(){
string str;
cin >> str;
bool flag = 0;
for(int i = 0;i < str.size();i ++) {
if(isdigit(str[i]) && str[i] != '0') {
flag = 1;
break;
}
}
if(!flag) cout << "YES" << endl;
else cout << "NO" << endl;
}
1002
- 题意
就是给你一颗树,每个节点都有一个颜色,定义(a_i,_j)表示从节点i到节点j颜色不同的数量,让你求
(f(i,19560929)=sum_{j=1}^n a_{i,j}x^{j-1})
这个公式中mod ((10^9+7)) 和 ((10^9+9))得出的不同值。
- 思路
emmm,我就是用以每个点为根,扫了一边dfs后加个预处理就过了昂(
逃)
code:
const int N = 2010;
const double INF = 1e9;
const int M = 2 * N;
ll ans[N][2];
ll f[N][N];
ll sum1[N], sum2[N];
int h[N],e[M],ne[M],w[N],idx;
bool st[N];
void add(int a,int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
int root;
void dfs(int u,int fa,int val) {
for(int i = h[u];~i;i = ne[i]) {
int j = e[i];
if(j == fa) continue;
f[root][j] = val;
bool flag = 0;
if(!st[w[j]]) {
st[w[j]] = 1;
flag = 1;
f[root][j] ++;
}
dfs(j,u,f[root][j]);
if(flag) {
st[w[j]] = 0;
}
}
}
void init() {
ll x = 19560929;
ll mod = 1e9 + 7;
sum1[0] = 1;
for(int i = 1;i <= 2000;i ++) {
sum1[i] = sum1[i - 1] * x % mod;
}
mod = 1e9 + 9;
sum2[0] = 1;
for(int i = 1;i <= 2000;i ++) {
sum2[i] = sum2[i - 1] * x % mod;
}
}
void solve(){
int n;
scanf("%d", &n);
idx = 0;
memset(h,-1,sizeof h);
for(int i = 2;i <= n;i ++) {
int x;
scanf("%d", &x);
add(i,x), add(x,i);
}
for(int i = 1;i <= n;i ++) scanf("%d", &w[i]);
for(int i = 1;i <= n;i ++) {
root = i;
f[i][i] = 1;
st[w[i]] = 1;
dfs(i,-1,1);
st[w[i]] = 0;
}
for(int i = 1; i <= n;i++){
ll sum = 0;
ll x = 19560929;
ll mod = 1e9 + 7;
for(int j = 1; j <= n; j++){
sum = (sum + f[i][j]%mod*sum1[j-1]%mod + mod)%mod;
}
sum %= mod;
ans[i][0] = sum;
mod = 1e9 + 9;
sum = 0;
for(int j = 1; j <= n; j++){
sum = (sum + f[i][j]*sum2[j-1]%mod + mod)%mod;
}
sum %= mod;
ans[i][1] = sum;
}
for(int i = 1; i <= n; i++){
cout << ans[i][0] << " " << ans[i][1] << endl;
}
}
1008
- 题意
一个僵尸,在(n * m)的地图的地图中走,并且只能想下和向右走,并且其中有k个障碍物,问你僵尸从(1,1)开始能到的所有点的数量
数据范围:(1<=t<=20) , (2<= n,m,k<= 10^5)
- 思路
考场上是按题解写的(用线段树维护上一层不能向下走的集合),没调出来,
还是t了,当时是k(log^2n写的),后面看std,又是维护上一层可行(可以向下走)的区域,都差不多吧~, 按照std的思想又码了一遍,还是太菜了,这个query和update中按照情况,还是L,R进行变动这个没想出来啊,呜呜呜--
code:
const int N = 100100;
const double INF = 1e9;
ll sum[2][N << 2],laz[2][N << 2];
void build(int u,int l,int r) {
sum[0][u] = sum[1][u] = 0;
laz[0][u] = laz[1][u] = -1;
if(l == r) {
return;
}
int mid = l + r >> 1;
build(u << 1, l, mid);
build(u << 1 | 1, mid + 1,r);
}
void down(int u,int l,int r, int k){
if(laz[k][u] == -1) return;
int mid = l + r >> 1;
ll la = laz[k][u];
sum[k][u << 1] = la * (mid - l + 1);
sum[k][u << 1 | 1] = la * (r - mid);
laz[k][u << 1] = la;
laz[k][u << 1 | 1] = la;
laz[k][u] = -1;
}
void update(int L,int R,ll v,int u,int l,int r,int k){
if(l >= L && r <= R){
sum[k][u] = v * (r - l + 1);
laz[k][u] = v;
return;
}
down(u,l,r,k);
int mid = l + r >> 1;
if(R <= mid) update(L, R, v, u << 1, l, mid,k);
else if(L > mid) update(L, R, v, u << 1 | 1,mid + 1, r,k);
else {
update(L,mid,v,u << 1,l,mid,k);
update(mid + 1,R,v,u << 1 | 1,mid + 1,r,k);
}
sum[k][u] = (sum[k][u << 1] + sum[k][u << 1 | 1]);
}
ll query(int L,int R,int u,int l,int r,int k){
if(!sum[k][u]) return INF;
if(l == r) return l;
down(u,l,r,k);
int mid = l + r >> 1;
if(l >= L && r <= R){
if(sum[k][u << 1] > 0) return query(l,mid,u << 1,l, mid,k);
else return query(mid + 1, r, u << 1 | 1, mid + 1, r,k);
}
if(R <= mid) return query(L,R,u << 1,l,mid,k);
else if(L > mid) return query(L,R,u << 1 | 1, mid + 1, r,k);
else return min(query(L,mid,u << 1,l,mid,k), query(mid + 1,R,u << 1 | 1, mid + 1, r,k));
}
vi p[N];
void solve(){
int n,m,k;
cin >> n >> m >> k;
for(int i = 1;i <= k;i ++) {
int a,b;
cin >> a >> b;
p[a].pb(b);
}
ll ans = 0;
build(1,1,m);
update(1,m,1,1,1,m,1); // 起点是可以的
if(p[1].size()) {
sort(p[1].begin(), p[1].end());
update(p[1][0], m,0,1,1,m,1);
}
ans += sum[1][1];
// 通过上一行的可行区域计算下一行的可行区域
for(int i = 2;i <= n;i ++) {
int l = 0;
sort(p[i].begin(), p[i].end());
for(int it : p[i]) {
if(it > l + 1) {
int pos = query(l + 1, it - 1, 1, 1, m,(i & 1) ^ 1); // 找上一层在l + 1 ~ it - 1之中,可行的最靠左的点
if(pos != INF) update(pos, it - 1, 1, 1, 1, m ,i & 1); // 那么左端点到it - 1都是可到达的区域
}
l = it;
}
if(l + 1 <= m) {
int pos = query(l + 1,m,1,1,m,(i & 1) ^ 1); // 同上
if(pos != INF) update(pos,m,1,1,1,m,i & 1);
}
ans += sum[i & 1][1];
update(1,m,0,1,1,m,(i & 1) ^ 1); // 清空,为下一层做准备
}
cout << ans << endl;
for(int i = 1;i <= n;i ++) p[i].clear();
}
1009
- 题意
给你30行字符串,每行100列,并且是个车牌,后5位字母或数组,第2位字母,第1位汉字。
- 思路
for两层,第一层从后往前,记录答案,最后第7个的时候不用记录,让l,r在那,然后输出即可
也就汉字能让我wa一发了0.0
code:
string str[31];
vector<pii> ans;
int now;
void solve(){
for(int i = 0;i < 30;i ++) {
cin >> str[i];
}
cout << "Case #" << (++ now) << ":" << endl;
int l = 0,r = 0;
for(int i = str[0].size() - 1;i >= 0;i --) {
bool flag = 0;
for(int j = 0;j < 30;j ++) {
if(str[j][i] != '.') {
flag = 1;
break;
}
}
if(flag && !l) l = i + 1;
else if(flag) r = i + 1;
if(!flag && l && r && ans.size() < 6) {
ans.push_back({r,l});
l = 0,r = 0;
}
}
cout << r << ' ' << l << endl;
for(int i = 5;i >= 0;i --) {
cout << ans[i].first << ' ' << ans[i].second << endl;
}
ans.clear();
}