TC SRM514 div2

  因为上次做TC,还是没有超过1200,所以下一场比赛还是要在div2做,所以还是训练div2.
  level 1:这一题我们只要区别离我们最近的是在边上还是在棱角上。这样我们并区别开之后,我们就可以完成了。
  level 2:因为我们有这样(n, 1), (n, -1), (-n, 1), (-n, -1), (1, n), (-1, n), (1, -n) or (-1, -n)八种选择,其实我们可以使用(n , 1),(1 , n) , (-1 , n) , (n , - 1)这样四种的多项式来表达,及
a * (n - 1) + b*(1 , n) + c * (-1 , n) + d*(n - 1) = (x , y)。在化解后,我们可以得到:
a = (n * k1 - k2 + x) / 2 ;
b = (-k2 - n * k1 - x) / 2; 
c = (n * k2 - k1 + y ) / 2;
d = (-k1 - y - n * k2) / 2;
这样我们要保证a , b , c , d都是整数就可以了。我们还可以发现,只要能保证a是整数,也能保证b是整数。同样c和d也是一样的。所以我们只要保证a 和 c是整数就可以了。这样我们可以对n, x , y进行讨论,看看能否存在k1,k2是的我们的a和c是整数。当n时偶数时,不管x,y的奇偶性,都是可以的。当n是奇数时,当x和y的奇偶性相同时就可以了。这样要注意是他们绝对值的奇偶性相同就可以了。
  level 3:计算在字符串[low ... high]之间的1的个数,我们只要分开算出字符串[0 .. high] 和 字符串[0 .. low - 1](注意当low是0的时候)差就可以了。因为str[n]的长度可能会很长,str[n] = str[n - 1] + str[n - 1 - k] + .....,因为high和low的长度是在long long 范围之内的,所以我们只要根据high和low来计算str[n]的前几项就可以了。附上代码:

const long long MAX =  1000000000000000000LL;
                       
typedef long long LL;

LL len[150];
LL ones[150];
bool hash[150];

class MagicalGirlLevelThreeDivTwo
{
        public:
        int theCount(vector <string> first, int n, long long lo, long long hi)
        {
			memset(hash , 0 , sizeof(hash));
			memset(len , -1 , sizeof(len));
			memset(ones , -1 , sizeof(ones));
			
			for (int i=0 ; i<first.size() ; i++) {
				len[i] = first[i].length();
				int oneCnt = 0;
				for (int j=0 ; j<first[i].length() ; j++) {
					if (first[i][j] == '1') {
						oneCnt++;
					}
				}
				ones[i] = oneCnt;
			}

			for (int i=first.size() ; i<=n ; i++) {
				LL lenTemp = 0;
				LL onesTemp = 0;
				bool flag1 = true;
				bool flag2 = true;

				for (int j=i - 1 ; j>=0 ; j -= first.size()) {
					if (flag1) {
						if (len[j] != -1) {
							lenTemp += len[j];
							if (lenTemp >= MAX) {
								flag1 = false;
							}
						}
						else {
							flag1 = false;
						}
					}
					if (flag2)
					{
						if (ones[j] != -1) {
							onesTemp += ones[j];
							if (onesTemp >= MAX) {
								flag2 = false;
							}
						}
						else {
							flag2 = false;
						}
					}
				}
				if (flag1) {
					len[i] = lenTemp;
				}
				else {
					len[i] = -1;
				}
				if (flag2) {
					ones[i] = onesTemp;
				}
				else {
					ones[i] = -1;
				}
			}

			LL ret = getNum(n , hi , first) - getNum(n , lo - 1 , first);
			return (int)ret;
        }

		LL getNum(int index , LL pos , vector<string>first) 
		{
			LL ret = 0;
			if (index < first.size()) {
				for (int i=0 ; i<=pos ; i++) {
					if (first[index][i] == '1')
						ret++;
				}
				return ret;
			}

			LL temp = 0;
			for (int i=index - 1 ; i>=0 ; i-=first.size()) {
				if  (check(i , first)) {
					LL iLen = len[i];
					if (temp + iLen - 1 >= pos) {
						return ret + getNum(i , pos - temp , first);
					}
					else {
						temp += iLen;
						ret += ones[i];
					}
				}
				else {
					return ret += getNum(i , pos - temp , first);
				}
			}
		}

		bool check(int index , vector<string> first) 
		{
			if (len[index] == -1) return false;
			return true;
		}
        

};


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值