SRM 452 DIV 1 总结

今天的TC依然如往日,250p恶搞简单,不过500p的竟然做起来比1000p的要难,1000p的参考了官方题解后终于A出来了,rng_58太神奇了~  今天又重温了昨天的500p,哎,想到要反着来,可惜还是没能自己想出,如果好好的画图观察下就能发现了。

250p:

题意:

给你一个n*m的棋盘,现在要在上面放石头,但是不能有两个石头的距离等于2,问最多能放多少个石头。


解题思路:

贪心的思路恶搞YY~


500p:

题意:

给你一个字符串,里面可以是 ‘I‘ ,  ’O‘,  ’?‘,?可以为I 也可以为O,定义一个IOI串:满足s[x] = I, s[x+y] = O, s[x+y+y] = I 的字符串,给你一个串,问能构成的不同的IOI串有多少个。


解题思路:

这题很容易想到反着来算,反着来算的话就是算串上没有间隔相等的IOI字符,所有情况很好算,现在我们就算不能构成IOI的字符串数。两个相隔最近的I , 如果相隔为偶数,那这样肯定不行,比如 IOOOI,相隔偶数的I中间必须要为I。那就可以知道了这样的串所有相隔最近的I相隔距离必须是奇数,如果某两个距离不相等,那么势必会造成有两个I相隔距离为偶数,比如

IOOOOIOOI,第一个I和第二个相隔5(奇数),第二个和第三个相隔3(奇数),那么第一个和第三个相隔肯定是偶数,就必须要把中间的变成I了。

最后推出结论,所有的I的间距必须相等且为奇数,这样子问题就很简单了,枚举第一个I的位置和I之间的间距,

时间复杂度最坏为O(n^2 * log n)


1000p:

题意:

定义一种数叫做递增数,也就是从最高位到最低位的位上的数是不下降的,比如1123,1345,1234,1122334

给你digits和divisor,1<=digits<= 10^18, 1<=divisor<=500 , 求位数为digits的且对divisor的余数为0的递增数有多少个,结果对1000000000+7取余。

一开始看到10^18,一般人很容易想到二分幂,我也刚开始这样想,但是这题是个例外。。。

这题的巧妙之处就在于递增数的性质,其实所有的递增数都可以表示为 1a + 11b + 111c + ... + ... (a + b + c + ..<= 9)

不懂的自己想想为什么把。由于divisor很小,最多也就500,我们可以把所有的满1状态的不同位数都表示成对divisor取余后的数,cnt[i]表示对divisor取余后为i的种数有多少种,这样就很简单了,直接转化成普通的背包问题,我们要把余数为i (0 <= i < divisor)的数看成物品,一个个加进去,因为a+b+c+... <= 9,所以状态就是dp[i][j][k]表示已经放了前i个余数总共放了k个数 (111 , 11, 1这些都看成一个数)且得到余数为j的有多少种情况。

可以参考官方题解 http://apps.topcoder.com/wiki/display/tc/SRM+452

250p   code:

#include <cstdio>
#include <cstring>
#include <cctype>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <iostream>
#include <map>
#include <set>
#include <list>
#include <sstream>
#include <queue>
#include <deque>
#include <stack>
#include <vector>
#include <bitset>
#include <algorithm>
using namespace std;
#define clr(a, x) memset(a, x, sizeof(a))
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define REP(i,a,b) for(int i=a;i<=b;i++)
template <class T> void checkmax(T &t, T x) { if (x > t) t = x; }
template <class T> void checkmin(T &t, T x) { if (x < t) t = x; }
template <class T> void _checkmax(T &t, T x) { if (t == -1 || x > t) t = x; }
template <class T> void _checkmin(T &t, T x) { if (t == -1 || x < t) t = x; }
typedef long long ll;
class NotTwo {
    public:
    int maxStones(int width, int height) ;


};

int NotTwo::maxStones(int w, int h)  {
    int ans = 0;
    int now = 0;
    while(now < w) {
        if(now%4 < 2) {
            if(h%4 <= 2)
                ans += h/4*2 + h%4;
            else
                ans += h/4*2 + 2;
        }else {
            if(h%4 == 3)
                ans += h/4*2 + 1;
            else
                ans += h/4*2;
        }
        now++;
    }
    return ans;
}


// Powered by FileEdit
// Powered by TZTester 1.01 [25-Feb-2003]
// Powered by CodeProcessor

500p code:

/* **********************************************
Author      : JayYe
Created Time: 2013-8-12 8:07:58
File Name   : Final.cpp
*********************************************** */

#include <cstdio>
#include <cstring>
#include <cctype>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <iostream>
#include <map>
#include <set>
#include <list>
#include <sstream>
#include <queue>
#include <deque>
#include <stack>
#include <vector>
#include <bitset>
#include <algorithm>
using namespace std;
#define clr(a, x) memset(a, x, sizeof(a))
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define REP(i,a,b) for(int i=a;i<=b;i++)
template <class T> void checkmax(T &t, T x) { if (x > t) t = x; }
template <class T> void checkmin(T &t, T x) { if (x < t) t = x; }
template <class T> void _checkmax(T &t, T x) { if (t == -1 || x > t) t = x; }
template <class T> void _checkmin(T &t, T x) { if (t == -1 || x < t) t = x; }
typedef long long ll;
class IOIString {
    public:
    int countIOIs(vector <string> mask) ;


};
bool mat[2502][2502], ri[2555];

const int mod = 1000000007;

int IOIString::countIOIs(vector <string> mask) {
    string s;
    int i, j;
    for(i = 0;i < mask.size(); i++) {
        for(j = 0;j < mask[i].size(); j++)
            s += mask[i][j];
    }
    int n = s.size();
    for(i = 0;i < n; i++) {
        int flag = 1;
        for(j = i+1;j < n; j++) {
            if(!flag)   mat[i][j] = 0;
            else if(s[i] != 'O' && s[j] != 'O') mat[i][j] = 1;
            if(s[j] == 'I') flag = 0;
        }
    }
    int flag = 1;
    for(i = n-1;i >= 0; i--) {
        if(flag) {
            ri[i] = 1;
            if(s[i] == 'I') flag = 0;
        }else {
            ri[i] = 0;
        }
    }
    printf("n = %d\n", n);
    int ans = 0;
    for(i = 0;i < n; i ++) {
        if(ri[i] && s[i] != 'O')   ans++;
        for(j = 1;j+i < n; j += 2) {
            int st = i, ed = i+j;
            while(mat[st][ed] && ed < n) {
                if(ri[ed])  ans++;
                st += j;ed += j;
            }
        //    printf("%d %d %d\n", i, j, ans);
        }
        if(s[i] == 'I') break;
    }
    if(i == n)  ans++;
    int ret = 1;
    for(i = 0;i < n; i++) if(s[i] == '?')
        ret = ret*2%mod;
    ret = (ret - ans)%mod;
    ret = (ret+mod)%mod;
    return ret;
}


// Powered by FileEdit
// Powered by TZTester 1.01 [25-Feb-2003]
// Powered by CodeProcessor




1000p  code:


/* **********************************************
Author      : JayYe
Created Time: 2013-8-11 15:50:47
File Name   : JayYe.cpp
*********************************************** */

#include <cstdio>
#include <cstring>
#include <cctype>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <iostream>
#include <map>
#include <set>
#include <list>
#include <sstream>
#include <queue>
#include <deque>
#include <stack>
#include <vector>
#include <bitset>
#include <algorithm>
using namespace std;

#define clr(a, x) memset(a, x, sizeof(a))
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define REP(i,a,b) for(int i=a;i<=b;i++)
template <class T> void checkmax(T &t, T x) { if (x > t) t = x; }
template <class T> void checkmin(T &t, T x) { if (x < t) t = x; }
template <class T> void _checkmax(T &t, T x) { if (t == -1 || x > t) t = x; }
template <class T> void _checkmin(T &t, T x) { if (t == -1 || x < t) t = x; }
typedef long long LL;
class IncreasingNumber {
    public:
    int countNumbers(LL digits, int divisor) ;

// BEGIN CUT HERE
	public:
	void run_test(int Case) { if ((Case == -1) || (Case == 0)) test_case_0(); if ((Case == -1) || (Case == 1)) test_case_1(); if ((Case == -1) || (Case == 2)) test_case_2(); if ((Case == -1) || (Case == 3)) test_case_3(); }
	private:
	template <typename T> string print_array(const vector<T> &V) { ostringstream os; os << "{ "; for (typename vector<T>::const_iterator iter = V.begin(); iter != V.end(); ++iter) os << '\"' << *iter << "\","; os << " }"; return os.str(); }
	void verify_case(int Case, const int &Expected, const int &Received) { cerr << "Test Case #" << Case << "..."; if (Expected == Received) cerr << "PASSED" << endl; else { cerr << "FAILED" << endl; cerr << "\tExpected: \"" << Expected << '\"' << endl; cerr << "\tReceived: \"" << Received << '\"' << endl; } }
	void test_case_0() { LL Arg0 = 26542766498659LL; int Arg1 = 25; int Arg2 = 766312864; verify_case(0, Arg2, countNumbers(Arg0, Arg1)); }
	void test_case_1() { LL Arg0 = 749886849151962303LL; int Arg1 = 1; int Arg2 = 661603623; verify_case(1, Arg2, countNumbers(Arg0, Arg1)); }
	void test_case_2() { LL Arg0 = 54126391707803701LL; int Arg1 = 39; int Arg2 = 779801725; verify_case(2, Arg2, countNumbers(Arg0, Arg1)); }
	void test_case_3() { LL Arg0 = 1LL; int Arg1 = 16; int Arg2 = 0; verify_case(3, Arg2, countNumbers(Arg0, Arg1)); }

// END CUT HERE

};
const int mod = 1000000007;

LL dp[555][555][11], vis[555];
int pos[555], val[555];

LL exgcd(LL a, LL b, LL &x, LL &y) {
    if(b==0) {
        x = 1; y = 0;
        return a;
    }
    LL ret = exgcd(b, a%b, y, x);
    y -= a/b*x;
    return ret;
}

LL C(LL n, int k) {
    if(k == 0)  return 1;
    LL x, y, ret = 1, i;
    for(i = 1;i <= k; i++)
        ret *= i;
    LL d = exgcd(ret, mod, x, y);
    x = (x%mod+mod)%mod;
    ret = x;
    for(i = n;i > n-k; i--) 
        ret = ret%mod*(i%mod);
    return ret;
}

int IncreasingNumber::countNumbers(LL digits, int divisor) {
    memset(vis ,0, sizeof(vis));
    memset(pos, 0, sizeof(pos));
    int pre = 0;
    int i, j, k, l, rr = 1%divisor;
    for(int i = 1;i < digits; i++) {
        int now = (pre*10+1)%divisor;
        val[i] = now;
        if(pos[now]) {
            digits -= pos[now]-1;
            LL mul = digits/(i-pos[now]);
            for(j = 1;j < pos[now]; j++)    vis[val[j]] ++;
            for(j = pos[now];j < i; j++) {

                vis[val[j]] += mul;
            }
            digits %= (i-pos[now]);
            if(digits == 0) {
                rr = pre;
                vis[rr]--;
                break;
            }
            for(j = 1;j < digits; j++)  {
                now = now%divisor;
                vis[now]++;
                now = (now*10+1)%divisor;
            }
            rr = now;
            break;
        }
        pos[now] = i;
        pre = now;
        if(i+1 == digits) {
            for(j = 1;j < digits; j++)
                vis[val[j]]++;
            rr = (now*10+1)%divisor;
        }
    }
    rr = divisor-rr;
    memset(dp, 0, sizeof(dp));
    dp[0][0][0] = 1;
    for(i = 0;i < divisor; i++) {
        for(j = 0;j < divisor; j++) {
            for(k = 0;k <= 8; k++) if(dp[i][j][k]){
                for(l = 0;l <= 8; l++) if(l+k <= 8) 
                    dp[i+1][(j+l*i)%divisor][l+k] =(dp[i+1][(j+l*i)%divisor][l+k] + dp[i][j][k] * (C(vis[i]+l-1, l)%mod))%mod;
            }
        }
    }
    LL ans = 0;
    for(i = 1;i <= 9; i++) {
        for(j = 0;j+i <= 9; j++)  ans = (ans+dp[divisor][(rr*i)%divisor][j])%mod;
    }
    return ans;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值