排位賽補題

我爆零了,佛了,看來方法不太對T_T;做題太容易先入爲主了,一錯到底。。。。
1.light oj 1077:How Many Points? (數論gcd)
題意:給定A(x1,y1),B(x2,y2)兩個點,求線段AB上有多少個點的x,y座標都是整數;
思路,一看就知道涉及到AB線段的斜率,不妨設其爲k = y/x;且這是將k的最簡分數,那麼就意味着橫座標每移動x,縱座標就會移動y,而二者都是整數,那麼我們就看能在線段上移動多少次,答案是gcd(x,y)次,由於還要起點也要算,所以+1;不要忘了特判斜率爲0或者不存在。

//#include<bits/stdc++.h>
#include<queue>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define mod (10007)
#define middle (l+r)>>1
#define SIZE 1000000+5
#define lowbit(x) (x&(-x))
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long ll;
typedef long double ld;
const int inf_max = 0x3f3f3f;
const ll Linf = 9e18;
const int maxn = 200+10;
const long double E = 2.7182818;
const double eps=0.0001;
using namespace std;
inline int read()
{
    int f=1,res=0;
    char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { res=res*10+ch-'0' ; ch=getchar(); }
    return f*res;
}
ll gcd(ll a,ll b) {
    return (b == 0? a : gcd(b,a%b));
}
int main()
{
    int t,cas = 1;
    cin>>t;
    while(t--) {
        ll x1,y1,x2,y2;
        cin>>x1>>y1>>x2>>y2;
        if(x1 == x2) {
            printf("Case %d: %lld\n",cas++,(max(y1,y2) + 1 - min(y1,y2)));
            continue;
        }else if(y1 == y2) {
            printf("Case %d: %lld\n",cas++,(max(x1,x2) + 1 - min(x1,x2)));
            continue;
        }
        ll disx = abs(x1-x2),disy = abs(y1-y2);
        printf("Case %d: %lld\n",cas++,gcd(disx,disy) + 1);
    }
    return 0;
}

2.鳴人和佐助 (計蒜客,BFS+優先隊列)
題意:給一個矩陣和鳴人初始查克拉,鳴人能追上佐助的最短時間,但是有個限制:地圖上有些點鳴人要花費查克拉纔可以進去,沒有查克拉就不能進去;
思路:我當時第一動的就是這個題(太明顯了,BFS+優先隊列),但是沒想清楚,如果單純地用vis數組給每個點打標記的話,假設一個點到了之後且這種情況下無法追上佐助,那麼答案就不存在,因爲其他點不能再走這個點;但實際上可能其他點也可能經過這個點並且能追上佐助,舉個例子就是:初始查克拉爲1

#@*
***
*##
**# 
*#+

直接打標記就結果就是追不上,然而實際上是可以追上的。所以,我們的策略應該是:只要此時走到某個點x的查克拉大於上一次走到這個點的查克拉,那麼都有可能達到我們想要的答案;

//#include<bits/stdc++.h>
#include<queue>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define mod (10007)
#define middle (l+r)>>1
#define SIZE 1000000+5
#define lowbit(x) (x&(-x))
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long ll;
typedef long double ld;
const int inf_max = 0x3f3f3f;
const ll Linf = 9e18;
const int maxn = 1000+10;
const long double E = 2.7182818;
const double eps=0.0001;
using namespace std;
inline int read()
{
    int f=1,res=0;
    char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { res=res*10+ch-'0' ; ch=getchar(); }
    return f*res;
}
struct STATUS {
    int x,y,t,ckl;
    bool operator<(const STATUS &a)const {
        return t > a.t;
    }
}s,e;
int dx[4] = {0,1,0,-1};
int dy[4] = {1,0,-1,0};
int vis[maxn][maxn],n,m,t;
char mp[maxn][maxn];
bool check(int x,int y) {
    if(x >= 1 && x <= n && y >= 1 && y <= m) return true;
    return false;
}
int bfs() {
    memset(vis,-1,sizeof(vis));
    priority_queue<STATUS>que;
    while(!que.empty()) que.pop();s.t = 0;s.ckl = t;
    que.push(s);vis[s.x][s.y] = t;
    while(!que.empty()) {
        STATUS u = que.top();que.pop();
        if(u.x == e.x && u.y == e.y) return u.t;
        for(int i = 0;i < 4; ++i) {
            int tx = u.x + dx[i],ty = u.y + dy[i];
            if(check(tx,ty) && u.ckl > vis[tx][ty]) { //這個點的查克拉必須要大於即將走到的點的查克拉,不然對於不消耗查克拉的點就會來回跑,不斷入隊導致mle:
                if(u.ckl == 0 && mp[tx][ty] != '#') {
                    STATUS tmp;tmp.x = tx;tmp.y = ty;tmp.ckl = 0;tmp.t = u.t + 1;
                    if(vis[tx][ty] <= tmp.ckl) {
                        que.push(tmp);vis[tx][ty] = tmp.ckl;
                    }
                }else if(u.ckl) {
                    STATUS tmp;tmp.x = tx;tmp.y = ty;tmp.t = u.t + 1;tmp.ckl = u.ckl;
                    if(mp[tx][ty] == '#') --tmp.ckl;
                    if(vis[tx][ty] <= tmp.ckl) {
                        que.push(tmp);vis[tmp.x][tmp.y] = tmp.ckl;
                    }
                }
            }
        }
    }
    return -1;
}
int main()
{
    while(~scanf("%d%d%d",&n,&m,&t)) {
        for(int i = 1;i <= n; ++i) {
            for(int j = 1;j <= m;++j){
                cin>>mp[i][j];
                if(mp[i][j] == '@') {
                    s.x = i;s.y = j;
                }
                if(mp[i][j] == '+') {
                    e.x = i;e.y = j;
                }
            }
        }
        printf("%d\n",bfs());
    }
    return 0;
}

3.Censor (scu-4438) (哈希)
題意:刪除給定字符串中的敏感串
思路:因爲刪去後,又可能形成新的敏感串,因此用棧可以快速得到刪去一個敏感串後的新串。模擬一個棧,把字符串加進去,如果位於棧頂部的一部分就是敏感串就刪去,字符串匹配的話就用哈希就可以。用stl的棧的話,每次刪除串就只有循環刪除,我寫t了,但是模擬的棧就可以O(1)刪除;

#include<bits/stdc++.h>
#include<queue>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define mod (1000000007)
#define middle (l+r)>>1
#define SIZE 1000000+5
#define lowbit(x) (x&(-x))
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int inf_max = 0x3f3f3f;
const ll Linf = 9e18;
const int maxn = 5e6 + 10;
const long double E = 2.7182818;
const double eps=0.0001;
using namespace std;
inline int read()
{
    int f=1,res=0;
    char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { res=res*10+ch-'0' ; ch=getchar(); }
    return f*res;
}
string ans;
char str[maxn],word[maxn],stk[maxn];
ll _hash[maxn],f[30],whash;
const ll seed = 233;
int main()
{
    //cout<<f['b']<<endl;
    while(~scanf("%s%s",word,str)) {
        memset(_hash,0,sizeof(_hash));
        whash = 0;
        ll p = 1;
        int wlen = strlen(word),slen = strlen(str);
        for(int i = 0;i < wlen; ++i) {
            whash = (whash * seed % mod + word[i]) % mod;
            p = (p * seed) % mod;
        }
        int top = 0;
        for(int i = 0;i < slen; ++i) {
            stk[++top] = str[i];
            _hash[top] = (_hash[top - 1] * seed % mod + stk[top]) % mod;
            while(top >= wlen) {
                ll cur = (_hash[top] - p * _hash[top - wlen] % mod + mod) % mod;
                if(cur == whash) top -= wlen;
                else break;
            }
        }
        for(int i = 1;i <= top;++i) {
            putchar(stk[i]);
        }
        puts("");
    }
    return 0;
}

4.Aninteresting game (hdu 5975)
題意:兩種操作:
求解[L,R]中所有數x的lowbit(x)之和。
給一個數x,求1~n中對於每個k,有多少個區間[k-lowbit(k) + 1,k]包含了數x
思路:
第一種操作:根據lowbit的定義,可以知道,每一個數的lowbit一定是2^k次方,那麼對於[L,R]中所有數的lowbit之和也就是1,2,4,8…這些數的和,採用前綴和的思想,先求出前綴,然後相減。考慮這些1,2,4,8每個有多少個:對於一個數num,num / 2表示[1,num]中可以被2整除的數,但是其中還可能包括被4,8,16整除的,所以根據容斥原理,我們就把能被4整除的數給減去。然後計算答案即可。
第二個操作:很明顯從樹狀數組中就可以看出,包含x的題意中的區間就是順着樹狀數組想上找。

#include<bits/stdc++.h>
#include<queue>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define mod (1000000007)
#define middle (l+r)>>1
#define SIZE 1000000+5
#define lowbit(x) (x&(-x))
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int inf_max = 0x3f3f3f;
const ll Linf = 9e18;
const int maxn = 5e6 + 10;
const long double E = 2.7182818;
const double eps=0.0001;
using namespace std;
inline int read()
{
    int f=1,res=0;
    char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { res=res*10+ch-'0' ; ch=getchar(); }
    return f*res;
}
ll n;
int q;
ll getsum(ll x){
    ll ret = 0;
    for(ll i = 0;(1ll << i) <= x; ++i) {
        //cout<<(1ll << i)<<endl;
        ll t1 = (1ll << i),t2 = (1ll << (i + 1));  //這裏由於範圍會超出int所以不能用int型的1來右移,會陷入死循環。
        ret += (x / t1 - x / t2) * t1;
    }
    return ret;
}
ll getsum3(ll x){
    ll ret = 0;
    ll tmp = 1;
    while(tmp <= x) {
        ret += (x / tmp - x / (tmp << 1)) * tmp,tmp <<= 1;
    }
    return ret;
}
ll query(ll x){
    ll ret = 0;
    while(x <= n) {
        ++ret;
        x += lowbit(x);
    }
    return ret;
}
int main()
{
    //cout<<getsum(4294967296)<<endl;
    while(~scanf("%lld%d",&n,&q)) {
        while(q--) {
            int t;
            cin>>t;
            if(t == 1) {
                ll l,r;
                scanf("%lld%lld",&l,&r);
                printf("%lld\n",getsum(r) - getsum(l - 1));
            }else if(t == 2) {
                ll x;
                scanf("%lld",&x);
                printf("%lld\n",query(x));
            }
        }
    }
    return 0;
}

題目
給n組數,每組m個數,還有一個K(對一組數中的第i個數作用會作用於所有第i組數的第i個數),用不超過k的cost把n組數中連續的一段的每一個數都變成0,求這個連續段的最長長度。
思路:枚舉左端點,二分從這個左端點開始的長度,然後查詢這個區間的最大值,我是想着用線段樹來維護最大值的,時間複雜度應該是O(nlognlogn)吧 ,感覺過是沒有問題的,但是T了,就很離譜。。。只有換一種查詢最大值的方法—rmq,這個我是真沒怎麼用過,查詢差不多又忘了。。,rmqO(nlogn)預處理,然後O(1)查詢,總的時間複雜度O(nlogn);

//#include<bits/stdc++.h>
#include<queue>
#include <cmath>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define mod (1000000007)
#define middle (l+r)>>1
#define SIZE 1000000+5
#define lowbit(x) (x&(-x))
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int inf_max = 0x3f3f3f3f;
const ll Linf = 9e18;
const int maxn = 1e5 + 10;
const long double E = 2.7182818;
const double eps=0.0001;
using namespace std;
inline int read()
{
    int f=1,res=0;
    char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { res=res*10+ch-'0' ; ch=getchar(); }
    return f*res;
}
int n,m,k,a[maxn][10],dp[10][maxn][20];

int main()
{
    while(~scanf("%d%d%d",&n,&m,&k)) {
        memset(dp,0,sizeof(dp));
        for(int i = 1;i <= n; ++i) {
            for(int j = 1;j <= m; ++j) {
                scanf("%d",&a[i][j]);
            }
        }
        for(int i = 1;i <= m; ++i)
            for(int j = 1;j <= n; ++j)
                dp[i][j][0] = a[j][i];
        for(int i = 1;i <= m; ++i) {
            for(int tt = 1;(1 << tt) <= n; ++tt) {  //由於狀態的轉移是從短區間來的,所以先把短區間更新了
                for(int j = 1;j + (1 << tt) - 1  <= n; ++j) {
                    dp[i][j][tt] = max(dp[i][j][tt - 1],dp[i][j + (1 << (tt - 1))][tt - 1]);
                }
            }
        }
        int anslen = 0,ansstart,flag = 0;
        for(int i = 1;i <= n; ++i) {  //枚舉左端點
            int l = 1,r = n + 1 - i,tmpans = 0;
            while(l <= r) {   //枚舉長度
                int mid = (l + r) >> 1,cost = 0,tt = log2(mid);
                int L = i,R = i + mid - 1;
                for(int j = 1;j <= m; ++j) {
                    cost += max(dp[j][L][tt],dp[j][R - (1 << tt) + 1][tt]);
                }
                if(cost > k) r = mid - 1;
                else {
                    l = mid + 1;
                    tmpans = mid;
                }
            }
            if(tmpans > anslen) {
                flag = 1;
                anslen = tmpans;
                ansstart = i;
            }
        }
        if(!flag)
            for(int i = 1;i <= m; ++i) printf("0%c",i==m?'\n':' ');
        else
            for(int i = 1;i <= m; ++i) {
                int l = ansstart,r = ansstart + anslen - 1;
                int tt = log2(anslen);
                printf("%d%c",max(dp[i][l][tt],dp[i][r - (1 << tt) + 1][tt]),i == m ? '\n' : ' ');
            }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章