codeforces #786 div3


A 签到

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

void solve()
{
    int a,b;
    cin >> a >> b;
    
    int cnt = 0;
    if(b % a) puts("0 0");
    else cout << 1 << " " << b / a << endl;
}

int main()
{
    int t;
    cin >> t;
    while (t -- ) solve();
    return 0;
}

B签到

#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>


using namespace std;
map<string,int> mp;

void solve()
{
    string s;
    cin >> s;
    
    cout << mp[s] <<endl;
}

int main()
{
    int t;
    int cnt = 1;
    
    for(char i = 'a';i <= 'z';i ++)
        for(char j = 'a';j <= 'z';j ++)
            if(i != j)
                {
                    string a = "";
                    a += i;
                    a += j;
                    mp[a] = cnt ++;
                }
    cin >> t;
    while (t -- ) solve();
    return 0;
}

C签到

#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>

using namespace std;
typedef long long LL;
LL ans = 0;
void solve()
{
    string s;string t;
    cin >> s >> t;
    
    int n = s.size(),m = t.size();
    for(int i = 0;i < m;i ++)
        if(t[i] == 'a' && m == 1){
            puts("1");
            return ;
        }
        else if(t[i] == 'a' && m > 1) {
            puts("-1");
            return ;
        }
    //cout <<  n << endl;
    cout << (1ll << n) << endl;
}

int main()
{
    int t;
    cin >> t;
    while (t -- ) solve();
    return 0;
}

D 思维
一开始想歪了,想通过局部去推公式
然后寄了,这个题目正确解法还是应该从操作本身入手,发现操作的本质,做这种题目应该多去模拟模拟,发现规律

#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>

using namespace std;
typedef long long LL;
const int N = 2e5 + 5;
int n,a[N];
int b[N];

void solve()
{
    cin >> n;
    for (int i = 1; i <= n; i ++ ) cin >> a[i];
     
    for(int i = n;i >= 1;i -= 2){
        if(i == 1) break;
        if(a[i - 1] > a[i])
            swap(a[i - 1],a[i]);
    }
    //for (int i = 1; i <= n; i ++ ) cout << a[i] << endl;
    
    for (int i = 1; i < n; i ++ )
        if(a[i] > a[i + 1])
            {
                puts("NO");
                return ;
            }
    puts("YES");        
}

int main()
{
    int t;
    cin >> t;
    while (t -- ) solve();
    return 0;
}

E贪心
这题分类讨论三中情况
赛时写寄了,写寄的那部分是相邻俩个数的情况
一开始以为相邻的俩个数,进行一次操作会消除3的贡献,但是发现并非如此,可能一个数通过这样的操作,他就会变为0,之后就无法贡献次数了,索引,在相邻俩个数之间应该进行一步贪心;
可以发现对大的进行-2的操作,对小的就是-1的操作,如此我们可以先将大的和小的进行变为相同的操作,同时应该对大的进行-2操作进行一个去min的操作,因为对大的-2不能减为负数,如果这么操作之后x和y还有剩余的话,进行-3的操作

#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>

using namespace std;
typedef long long LL;
const int N = 2e5 + 5;
int n,a[N];

void solve()
{
    cin >> n;
    for (int i = 1; i <= n; i ++ ) 
        cin >> a[i];
    //俩种位置贪心选
    //隔山打牛
    //俩个相邻的位置 -2,-1
    int ans = 0x3f3f3f3f;
    for (int i = 1; i <= n - 2; i ++ )
        ans = min(ans,(a[i] + a[i + 2] + 1) / 2);
        
    for (int i = 1; i <= n - 1; i ++ ){
        //ans = min(ans,(a[i] + a[i + 1] + 2) / 3);
        //错误的贡献法,因为当一个数变为0的时候
        //他就贡献不了次数了
        //所以不能按总值来算
        int cur = 0;
        int x = a[i], y = a[i + 1];
        if (x < y) {
            swap(x, y);
        }
        int cnt = min(x - y, (x + 1) / 2);
        cur += cnt;
        x -= 2 * cnt;
        y -= cnt;
        if (x > 0 && y > 0) {
            cur += (x + y + 2) / 3;
        }
        ans = min(ans, cur); 
    }
    sort(a + 1,a + n + 1);
    ans = min(ans,(a[1] + 1) / 2 + (a[2] + 1) / 2);
    
    cout << ans << endl; 
}

int main()
{
    int t;
    //cin >> t;
    t = 1;
    while (t -- ) solve();
    return 0;
}

F 思维

实现可以用树状数组或者直接维护
树状数组

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;
const int N = 1005 * 1005;
char a[1005][1005];
int n,m,q;
int tr[N];

int lowbit(int x)
{
    return x & -x;
}

void update(int x, int c)  // 位置x加c
{
    for (int i = x; i <= n * m; i += lowbit(i)) tr[i] += c;
}

int query(int x)  // 返回前x个数的和
{
    int res = 0;
    for (int i = x; i; i -= lowbit(i)) res += tr[i];
    return res;
}

void solve()
{
    cin >> n >> m >> q;
    for(int i = 1;i <= n;i ++)
        for(int j = 1;j <= m;j ++){
            cin >> a[i][j];
            int t = i + (j - 1) * n;
            if('*' == a[i][j]) update(t,1);
        }
    
    while(q --){
        int x,y;
        cin >> x >> y;
        int t = x + (y - 1) * n;
        
        if(a[x][y] == '*') {
            update(t,-1);
            a[x][y] = '.';
        }
        else {
            update(t,1);
            a[x][y] = '*';
        }
        
        int cnt = query(n * m);
        cout << cnt - query(cnt) << endl;
    }
}

int main()
{
    int t;
    t = 1;
    while (t -- ) solve();
    return 0;
}

直接维护

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;
const int N = 1005 * 1005;
int a[N];
int n,m,q;

void solve()
{
    cin >> n >> m >> q;
    int sum = 0;
    for(int i = 1;i <= n;i ++)
        for(int j = 1;j <= m;j ++){
            int t = i + (j - 1) * n;
            char x;
            cin >> x;
            if(x == '*') {a[t] = 1;sum ++;}
        }
    int cnt = 0;
    for(int i = 1;i <= sum;i ++) cnt += a[i];
    int ans = sum - cnt;
    
    //cnt 表示sum前面的个数
    //sum 表示应该插的位置在哪
    while (q -- ){
        int x,y;
        cin >> x >> y;
        int t = x + (y - 1) * n;
        
        if(a[t] == 0){
            a[t] = 1;
            if(t > sum) ans ++;
            sum ++;
            if(a[sum]) ans --;
        }
        else {
            a[t] = 0;
            if(t > sum) ans --;
            if(a[sum]) ans ++;
            sum --;
        }
        
        cout << ans << endl;
    }
}

int main()
{
    int t;
    t = 1;
    while (t -- ) solve();
    return 0;
}

G top排序 + DP
top序的概念 在DAG中,任俩个点 i,j 要么 i 到 j,要么 j 到 i。
首先抽象出来题目的大意
如果一个点存在入度或者出度的话,每一个点的入度和出度都必须减一。
然后考虑DP,首先这是一个DAG,所以在DAG上DP,应该先进行一下top排序,故在top排序的时候进行状态转移 ———— 路径上的每一个点都应该满足前驱节点的出度大于一,后驱节点的入度大于二这样才能转移,注意DP的初始化

#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>

using namespace std;
typedef long long LL;
const int N = 2e5 + 5,M = N << 1;
int h[N], e[M], ne[M], idx;
int n,a,b,m;
int in[N],out[N];
int q[N],tt = -1,hh;
int dp[N];//表示以i为节点的合法方案
int top[N];

void add(int a, int b)  // 添加一条边a->b
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}

void solve()
{
    cin >> n >> m;
    memset(h, -1, sizeof h);
    
    for(int i = 1;i <= m;i ++){
        cin >> a >> b;
        add(a, b);
        
        top[b] ++;
        in[b] ++;
        out[a] ++;
    }
    
    for(int i = 1;i <= n;i ++)
        if(!top[i]){
            q[++ tt] = i;
            dp[i] = 1;//dp初始化
        }
        
    int ans = 1;    
    while(hh <= tt){
        auto u = q[hh ++];
        //cout << u << endl;
        
        for(int i = h[u]; ~i ;i = ne[i]){
            int j = e[i];
            
            if(out[u] > 1 && in[j] > 1){
                //cout << " ---- " << endl;
                dp[j] = max(dp[j],dp[u] + 1);
                ans = max(dp[j],ans);
                //cout << dp[j] << endl;
            }
            
            if(!--top[j]){
                q[++ tt] = j;
                if(!dp[j]) dp[j] = 1;
            }
        }
    }
    
    cout << ans << endl;
}

int main()
{
    int t;
    //cin >> t;
    t = 1;
    while (t -- ) solve();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值