暑假第二测

题解:

第一题:

如果A矩形的前缀和MOD K = P, C矩形的前缀和MOD K =P,说明中间的矩形MOD K= 0; 所以枚举列起点, 终点, 行数, 统计余数出现次数 O(n*M*M);

#include <bits/stdc++.h>
const int M = 405, N = 1e6 + 10;
using namespace std;
#define rt register
int a[M][M], sum[M][M], vis[N], lie[M][M], ret[M];
int main()
{
    //freopen("rally.in", "r", stdin);
    //freopen("rally.out", "w", stdout);
    int n, m, k;
    long long cnt = 0;
    scanf("%d%d%d", &n, &m, &k);
    for(rt int i = 1; i <= n; i++)
        for(rt int j = 1; j <= m; j++){
            scanf("%d", &a[i][j]);
            sum[i][j] = (sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + a[i][j]) % k;
            lie[i][j] = lie[i][j-1] + a[i][j];
        }
        for(int i = 1; i <= m; i++)
            for(int j = i; j <= m; j++){
                for(int p = 1; p <= n; p++){
                    ret[p] = (ret[p-1] + lie[p][j] - lie[p][i-1]) % k;
                    vis[ret[p]] = 0;
                }
                for(int p = 1; p <= n; p++){
                    if(ret[p] == 0) cnt++;
                    cnt += vis[ret[p]];
                    vis[ret[p]]++;
                }
            }

    printf("%lld", cnt);
    return 0;
}

第二题:

45 分做法  k == 1 dp
dp[u][0] control by son dp[u][1] control by oneself dp[u][2] control by father
dp[u][0] = sum(min(dp[v][0], dp[v][1]) (but there must be at least one dp[v][1])
dp[u][1] = sum(min(dp[v][0/1/2])
dp[u][2] = sum(min(dp[v][0],dp[v][1]))

dp:

void dfs(int u, int f){
    fa[u] = f;
    int delta = inf, sum = 0, child = 0;
    for(int i = h[u]; i; i = G[i].nxt){
        int v = G[i].v;
        if(v == f)continue;
        child++;
        dfs(v, u);
        sum += min(dp[v][1], dp[v][0]);
        delta = min(delta, max(dp[v][0] - dp[v][1], 0));
        if(dp[v][0] < dp[v][1]) pp[u] = 1;
        dp[u][0] += min(dp[v][1], min(dp[v][0], dp[v][2]));
    }
    if(!child){
        dp[u][1] = inf; dp[u][0] = 1;
        return ;
    }
    dp[u][0]++;
    dp[u][1] = dp[u][2] = sum;
    if(!pp[u]) dp[u][1] += delta;
}

AC code

#include <bits/stdc++.h>
const int M = 1e5 +10;
#define inf 1e8
using namespace std;
int tot, n, k, fa[M], t, dep[M], h[M];
bool vis[M];
struct edge{int v,nxt;}G[M<<1];
void add(int u, int v){G[++tot].nxt = h[u]; h[u] = tot; G[tot].v = v; }
void dfs(int u, int f){
    dep[u] = dep[f] + 1;
    fa[u] = f;
    for(int i = h[u]; i; i = G[i].nxt){
        int v = G[i].v;
        if(v == f)continue;
        dfs(v, u);
    }
}
void dst(int u, int dd, int f){
    vis[u] = 1;
    for(int i = h[u]; i; i = G[i].nxt){
        int v = G[i].v;
        if(v == f)continue;
        if(dd < k)dst(v, dd+1, u);
    }
}
struct Node{
    int id, dep;
    bool operator < (const Node& a)const{
        return a.dep > dep;
    }
};
priority_queue <Node> Q;
int main()
{
    int cnt = 0;
    scanf("%d%d%d", &n, &k, &t);
    for(int i = 1; i < n; i++){
        int u, v;
        scanf("%d%d", &u, &v);
        add(u, v); add(v, u);
    }
    dfs(1, 0);
    for(int i = 1; i <= n; i++)
        Q.push((Node){i, dep[i]});
    for(int i = 1; i <= n; i++){
        int aa = Q.top().id;
        Q.pop();
        if(vis[aa])continue;
        int tt = 0;
        while(tt < k){
            if(!fa[aa])break;
            aa = fa[aa];
            tt++;
        }
        dst(aa, 0, aa);
        //printf("%d ", aa);
        cnt++;
    }
    printf("%d\n", cnt);
    return 0;
}

第三题:首先我们发现对于连续的一段灯泡去按它的开关极其费时,因此我们需要一种O(1)复杂度的方法进行开关的操作。

对于序列加减我们可以用差分数组, 对于异或也可以差分;

令差分数组 b[i] = a[i]^a[i+1]  例:

a    1 0 0 0 1

b 1 1 0 0 1 1

将1——5翻转, 则修改B[0] 和 b[5] 就可以了

b 0 1 0 0 1 0

a    0 1 1 1 0

b逆推的a如上; 一个1 会在B中产生至多两个1, 故最多2k个1.,那么原问题被我们玄学的转化为了对于给定的0 1数列,每次对于按要求的某两个数进行取反,问最少次可以使数列全部变为1.

这里有必要提一下原问题麻烦的地方,即对于答案无用的灯泡(亮着的)太多,这样会导致进行大量的无效操作。所以我们只对有1的地方操作,那么他们转化的状态我们就达到某状态的最小操作次数可以预处理出来,最后答案为全0的状态; 这个可以用SPFA跑, 然后由于只有2k个1,我们就可以状压了;

#include<bits/stdc++.h>
using namespace std;
const int N = 1<<18,M = 40005, inf = 1e8;
int a[M], ans, b[M], cnt;
int n, k, m, dis[20][M];
int dp[N];
typedef pair<int, int> pii;
pii p[20];
void bfs(pii st){
    queue <int> q;
    for(int i = 0; i <= n; i++) dis[st.first][i] = inf;
    q.push(st.second);
    dis[st.first][st.second] = 0;
    while(!q.empty()){
        int u = q.front(); q.pop();

        for(int i = 1; i <= m; i++){
            if(u + b[i] <= n && dis[st.first][u] + 1 < dis[st.first][u + b[i]]){
                dis[st.first][u + b[i]] = dis[st.first][u] + 1;
                q.push(u + b[i]);
            }
            if(u - b[i] >= 0 && dis[st.first][u] + 1 < dis[st.first][u - b[i]]){
                dis[st.first][u - b[i]] = dis[st.first][u] + 1;
                q.push(u - b[i]);
            }
        }

    }

}

int solve(int sta){
    //printf("%d\n", sta);
    if(dp[sta] != -1)return dp[sta];
    if(sta == 0)return 0;
    dp[sta] = inf;
    int fi = 0;
    while(!((1<<fi)&sta))fi++;
    for(int i = fi+1; i < 2*k; i++)
        if( (1<<i) & sta )
            dp[sta] = min(dp[sta], dis[fi][p[i].second] + solve(sta^(1<<fi)^(1<<i)));
    //printf("%d %d\n", sta, dp[sta]);
    return dp[sta];
}

int main(){
    //freopen("starlit.in","r",stdin);
    //freopen("starlit.out","w",stdout);
    scanf("%d%d%d", &n, &k, &m);
    for(int i = 1; i <= k; i++){
        int v;  scanf("%d", &v);
        a[v] = 1;
    }
    for(int i = 1; i <= m; i++)scanf("%d", &b[i]);
    for(int i = 0; i <= n; i++)
        if(a[i] != a[i+1]) p[cnt] = pii(cnt++, i);
    for(int i = 0; i < cnt; i++) bfs(p[i]);
    memset(dp, -1, sizeof(dp));
    int ans = solve((1<<cnt)-1);
    printf("%d",ans);
}

原文地址:https://www.cnblogs.com/EdSheeran/p/9299157.html

时间: 2024-10-11 00:22:29

暑假第二测的相关文章

暑假第二周&#183;1,2

最近有点散漫,散漫到挤不出时间写进度日记.这个星期我开始编写要用到的网页,星期天的晚上我拿到样图,但是星期一,我差不多一天都在编写不需要写的首页.我以为发给我的都是要做的,被学姐说了之后我发现一天下来什么也没做!在那天晚上我将其余网站的“代码”写好了. 当第二天的试运行让我看到了什么叫做门外汉,我又花了一个下午在修改上才能让我写的代码能够运行正常.我被代码折腾的晕头转向,却也为写好了代码感到高兴.我兴冲冲的拿给学姐检查,但学姐指出的地方让我发现我并没有身为美工的自觉.在我为代码而苦恼的时候并没有

开学第二测

开学第二测(好像是qbxt zhx出的题) P69 题目名称 希望 残  党 名称    kami na wosa 输入  kami.in   na.in wosa.in 输出  kami.out na.out  wosa.out 每个测试点时限 1 秒 1 秒 1 秒 内存限制 512MB 512MB 512MB 测试点数目  10 10 10 每个测试点分值  10 10 10 是否有部分分 无 无 无 题目类型 传统 传统 传统  注意 事项(请务必仔细阅读):   T1 希望[题目描述]

从使命召唤手游国际版将于暑假公测 谈论代理IP在游戏中的作用

本文关键词:代理IP,手机代理IP软件 从使命召唤手游国际版将于暑假公测 谈论代理IP在游戏中的作用 使命召唤手游官方3月18日发布了最新爆料,正式宣布<使命召唤>国际版将于今年暑假进行公测! 目前游戏官网已开启了预注册.根据官网此次的消息,基本可以大胆预测如果国内版号顺利,<使命召唤>国服也将很快与大家见面了! 此次<使命召唤>国际版的预注册现已在部分地区开放,比如北美,南美,欧洲和其他地区,包含 Android 和 iOS . 保留系列经典模式 并将推出额外模式 &

暑假第二周报告

暑假第二周,小学期结束后回到了家.用一天的时间进行休整,同时列出了自己暑假需要做的所有事情,并列了一个简单的计划. 首先,在这周每天中午.晚上睡觉前,我会看半到一个小时<大道至简>.然后这一周初步接触了Java,并在自己的电脑上搭建了Java环境,也就是有关jdk的下载及相关环境的配置:还有下载安装了eclipse并进行了配置:完成之后我尝试了“helloworld.Java”的编译. 除此之外,在这一周里,每天下午有一个小时左右的时间,开始学习Java语言的最基础的部分.到目前为止,每天学习

暑假第二十五测

以后WA了T了看数组: 暑假四次数组下标超界,多次数组开小,暂时没有访问到负下标 题解: 第一题:这道题可以转换为颜色相同的点缩成一个点,每次可以将两个点合并成同一点,问最少几次将所有点合并成一个点: 开始想到并查集+贪心合并度数最多的并查集,但这样是有问题的,比如度数一样时,选择的先后顺序是有影响的: 正解:缩点+找直径,如果是一条黑白相间的链,就是点数/2, 而树上任何一条直径都会有一个点经过直径,我们从交点开始往外延伸,发现最长延伸就是直径本身: 思想:从特殊到一般 #include<bi

暑假第二十四测

题解: 第一题:二分+贪心:二分距离上限,两端的人能从两端取就从两端取,这样可以为中间的做贡献: #include<bits/stdc++.h> using namespace std; const int M = 10005; int a[M], b[M], pos[M], x, n, m; bool id[M]; #define ll long long inline int ab(int a, int b){ if(a > b)return a - b; return b - a;

暑假第二十六测

今天又考的奇差 题解: 第一题: 这么简单一道题我想了好久,智商实在是下线了: #include<bits/stdc++.h> using namespace std; int main(){ freopen("shortway.in","r",stdin); freopen("shortway.out","w",stdout); int n, k; scanf("%d%d", &n,

暑假第二十九测

第三题换成能否得到x, 可以1, 不可以-1 题解: 第一题:打表找规律: 打表发现a是:1 1 2 2 3 4 4 4 5 6 6 7 8 8 8 8 9-- 对于每一项Ai = i拆分成质因数中有多少个2 + 1:如果把桶也给打出来,就发现他是这样的: 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 2 + 4 + 6 + 8 +  4  + 8 +  8 + 即2^i的等差数列,所以对一个数m我们就很容易确定他前面的数的和: 但是对于一个位置我们怎么找到他对应的m呢? 把上

暑假第二次考试 冲刺Noip2017模拟赛2 解题报告——五十岚芒果酱

题1 牛跑步(running) [题目描述] 新牛到部队,CG 要求它们每天早上搞晨跑,从 A 农场跑到 B 农场.从 A 农场到 B 农场中有 n-2 个路口,分别标上号,A 农场为 1 号,B 农场为 n 号,路口分别为 2...n-1 号,从 A 农场到 B 农场有很多条路径可以到达,而 CG 发现有的路口是必须经过的,即每条路径都经过的路口,CG 要把它们记录下来,这样 CG 就可以先到那个路口,观察新牛们有没有偷懒,而你的任务就是找出所有必经路口. [输入格式] 第一行两个用空格隔开的