18.8.16 考试总结

我的天啊今天竟然16号了...?? 不 我不要开学...!! 我要烂死在机房里面...!!!

完美子串
【问题描述】 yyc非常喜欢完美的字符串 ,当然一个完美的字符串定是简约并且多样的。

现在 yyc 有一个字符串,他想知道这个字符串的完美子最小长度是多少。

一个完美子串,是原来的一个连续子序列并且包含了不同的26个大写字母。

当然了 如果yyc的字符串中并不存在完美子串 ,则输出QwQ 。


【输入格式】
从文件 str .in 中输入数据。
第一行, 1个字符串。


【输出格式】
输出到文件 str .out中。
共一行, 表示最短长度。无解则输出 QwQ

 

这道题还是比较简单的 看完题想了一会儿就想出来了

就是二分可行的最短长度 然后O(n)判断是否可行 就用一个滑动窗口每次加减元素

然后开一个vis数组表示对应字符出现的次数 (当然你只用保存A - Z的字符出现次数就可以了)

再开一个tmp表示滑动窗口里面26个大写字母已经出现了多少个

然后每次入队的时候如果他之前出现次数为0 那tmp就++ 

同样的 如果出队的时候它的vis减为0 那么tmp -- 一旦tmp == 26 就直接return true 否则完了都还没有就return false

还有stl真的好他妈的慢啊...!!! 垃圾队列害我在cena上面t了一个点

代码

#include <bits/stdc++.h>
using namespace std;

const int N = 2 * 1e6 + 5;
char s[N],Q[N];
int l,r,vis[26],len;

bool check(int c) {
    
    memset(vis,0,sizeof(vis));
    int tmp = 0;
    int head = 0,tail = 0;
    for(register int i = 1;i <= len;i ++) {
        int siz = tail - head;
        if(siz == c) {
            char u = Q[head + 1];
            if(u >= 'A' && u <= 'Z') {
                vis[u - 'A'] --;
                if(vis[u - 'A'] == 0) tmp --;
            }
            head ++;
        }
        Q[++ tail] = s[i];
        if(s[i] >= 'A' && s[i] <= 'Z') {
            if(vis[s[i] - 'A'] == 0) tmp ++;
            vis[s[i] - 'A'] ++;
        }
        if(tmp == 26) return true;
    }
    return false;
}

void solve( ) {
    
    int ans = 0;
    l = 26,r = len;
    while(l <= r) {
        int mid = (l + r) >> 1;
        if(check(mid)) {
            ans = mid;
            r = mid - 1;
        }
        else l = mid + 1;
    }
    if(ans > 0) printf("%d",ans);
    else printf("QwQ");
}

int main( ) {
    
    freopen("str.in","r",stdin);
    freopen("str.out","w",stdout);
    scanf("%s",s + 1);
    len = strlen(s + 1);
    solve( );
}

游戏
【问题描述】
everlasting觉得太无聊了,于是决定和蒟蒻 yyc 玩游戏!
他们会玩T轮游戏,每轮中有若干局。他们的初始积分为 1,每局的分值为k。

输的人得分乘k,赢的人得分乘k2。每轮游戏后, everlasting都会询问这 都会询问这次游戏双方的得分,

但 yyc 记不住得分,只能随口说两个 。但他不知道这两个数最终会不会成为两个人的得分。于是 yyc 决定向你求助!

 

【输入格式】
从文件game.in 中输入数据。
第一行1个正整数T,表示游戏轮数。接下来每行两个数,表示 yyc 随口说出的两个人得分。

 

【输出格式】
输出到 文件game.out 中。
T行,每行一个“ Yes ”或“ No ”。 表示这两个数是否合法。

 

前面几行都是废话 正解在加粗的地方

考试的时候乱搞了一个垃圾算法狗了55分...虽然我觉得我这个垃圾算法还是挺正确的

原来的想法是 对于每一局游戏 两方都同时至少乘了一个k 所以说他们的gcd里面至少都有每轮游戏的k之积

然后x y分别除以gcd多余的部分就是那个多乘的k 在判断他们的多余部分之积是否等于gcd就好了

但是光是求gcd的话会出问题 就可能我一轮游戏是2k 另一轮是k

按照原来的思路搞出来多余部分之积应该是2k2  这样子求gcd再除下来x y就会变得很小

因为原来这样子除以搞出来两部分肯定互质 但有可能他们原来不互质 就除多了

但是我肯定不会除少 所以我就在1 - gcd里面二分(满足二分性) 判断答案是否合法就可以了

但是我wa了不少  有可能是我垃圾二分写挂了

挖我竟然说了这么多废话  以上都是在扯淡..

正解简单得不得了 对于最后分数x,y 都可以把他当做两轮游戏的最终分数

把它赢得局获得的分数丢到一堆  输的丢到一堆 -> x = k12 * k2 ,y = k22 * k1 

k1表示x赢y输 k2相反 所以说这样子x * y = k13 * k23  所以我们就只用二分判断这两个数的积是不是一个数的立方就可以了

代码

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
ll T,x,y;

ll read( ) {
    
    ll ans = 0,t = 1;
    char x; x = getchar( );
    while(x < '0' || x > '9') {
        if(x == '-') t = -1;
        x = getchar( );
    }
    while(x >= '0' && x <= '9') {
        ans = ans * 10 + x - '0';
        x = getchar( );
    }
    return ans * t;
}

ll check(ll x) {
    
    ll l = 1,r = 1e6;
    while(l <= r) {
        ll mid = (l + r) >> 1;
        if(mid * mid * mid == x) return mid;
        else if(mid * mid * mid > x) r = mid - 1;
        else l = mid + 1;
    }
    return -1;
}

int main( ) {
    
    freopen("game.in","r",stdin);
    freopen("game.out","w",stdout);
    cin >> T;
    while(T --) {
        x = read( ); y = read( );
        ll s = check((x * y));
        if(s != -1 && x % s == 0 && y % s == 0) printf("Yes\n");
        else printf("No\n"); 
    }
}

泥泞的牧场
【问题描述】 大雨侵袭了牧场.牧场是一个 R * C 的矩形,其中1≤R ,C≤50。

大雨将没有长草的土地弄得泥泞不堪,可是小心的奶牛们不想在吃草时候脏她们的蹄子。为了防止她们的蹄子被弄脏,

农场主决定在泥泞的牧场里放置一些木板。每块木板的宽度为 1个单位,长度任意.每一个板必须放置在平行于牧场的泥地里

农场主最少的木板覆盖所有的泥地 。 一个木板可以重叠在另一个木板上,但是不能放草地。

 

【输入格式】
从文件 cover.in 中输入 数据。
第一行:两个整数 R 和 C,1 ≤ R,C ≤ 50
第二行到R + 1 行:每行有 C 个字符,表示该行的地形。" * "代表泥地,“ .”代表草地。


【输出格式】
输出到 文件 cover.out 中。
一个整数:表 示最少需要多木板 。

 

这道题听过好几遍了 就是一道二分图跑最大匹配 也可以弄成网络流跑最小割 总之就是求一个最小点覆盖

建图方法是 对于横着的泥地连续的编号 纵的也编号 然后对于每块泥地从它横着的编号向纵着的连一条容量为1的边

然后源点连向横着的编号 纵着的编号连向汇点

编号方法 我举个例子吧 

至于求最小割的原因就是要使每一块泥地都被覆盖 显然如果某编号泥地的木板被割掉了 同一个编号的泥地就也被覆盖了

所以就只用割掉一块木板 就割掉了一堆泥地 所以就跑一个最小割

代码

#include <bits/stdc++.h>
#define oo 1e9
using namespace std;

const int M = 4 * 1e6;
const int N = 1e5 + 10;
int r,c,src,sink,c1[51][51],c2[51][51],num1,num2,h[N];
int head[N],nex[M],tov[M],f[M],tot = 1,dis[N];
char s[51][51];
bool vis[N];
queue<int>Q;

void init( ) {
    
    int col = 0;
    for(int i = 1;i <= r;i ++) {
        for(int j = 1;j <= c;j ++) {
            if(j == 1 && s[i][j] == '*') c1[i][j] = ++ col;
            else if(s[i][j] == '*' && s[i][j - 1] == '*') c1[i][j] = col;
            else if(s[i][j] == '*' && s[i][j] != s[i][j - 1]) c1[i][j] = ++ col;
        }
    }
    num1 = col;
    
    col = 0;
    for(int i = 1;i <= c;i ++) {
        for(int j = 1;j <= r;j ++) {
             if(j == 1 && s[j][i] == '*') c2[j][i] = ++ col;
             else if(s[j][i] == '*' && s[j - 1][i] == '*') c2[j][i] = col;
            else if(s[j][i] == '*' && s[j][i] != s[j - 1][i]) c2[j][i] = ++ col;
        }
    } 
    num2 = col;
    src = 1,sink = 2 + num1 + num2;
}

void add(int u,int v,int fl) {
    
    tot ++;
    tov[tot] = v;
    nex[tot] = head[u];
    f[tot] = fl;
    head[u] = tot;
    tot ++;
    tov[tot] = u;
    nex[tot] = head[v];
    f[tot] = 0;
    head[v] = tot;
}

void add_edge( ) {
    
    for(int i = 1;i <= r;i ++)
      for(int j = 1;j <= c;j ++) {
          if(s[i][j] == '*') {
              add(1 + c1[i][j],1 + num1 + c2[i][j],1);
          }
      }
    for(int i = 2;i <= 1 + num1;i ++) add(src,i,1);
    for(int i = 2 + num1;i <= 1 + num1 + num2;i ++) add(i,sink,1);
}

bool bfs( ) {
    
    memset(vis,0,sizeof(vis));
    memset(dis,0,sizeof(dis));
    vis[src] = true;
    Q.push(src);
    while(! Q.empty( )) {
        int u = Q.front( ); Q.pop( );
        for(int i = head[u];i;i = nex[i]) {
            int v = tov[i];
            if(f[i] && (! vis[v])) {
                dis[v] = dis[u] + 1;
                vis[v] = true;
                Q.push(v);
            }
        }
    }
    return vis[sink];
}

int dfs(int u,int delta) {
    
    if(u == sink) return delta;
    int res = 0;
    for(int & i = h[u];i;i = nex[i]) {
        int v = tov[i];
        if(f[i] && dis[v] == dis[u] + 1) {
            int flow = min(delta,f[i]);
            int del = dfs(v,flow);
            res += del;
            delta -= del;
            f[i] -= del;
            f[i ^ 1] += del;
        }
    }
    return res;
}

int main( ) {
    
    freopen("cover.in","r",stdin);
    freopen("cover.out","w",stdout);
    scanf("%d%d",& r,& c);
    for(int i = 1;i <= r;i ++) scanf("%s",s[i] + 1);
    init( );
    add_edge( );
    int ans = 0;
    while(bfs( )) {
        for(int i = src;i <= sink;i ++) h[i] = head[i];
        ans += dfs(src,oo);
    }
    printf("%d",ans);
}

 

转载于:https://www.cnblogs.com/Rubenisveryhandsome/p/9487375.html

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值