contesthunter暑假NOIP模拟赛#1题解:

第一题:杯具大派送

水题。枚举A,B的公约数即可。

#include <algorithm>
#include <cmath>
#include <iostream>
using namespace std;
#define MAXN 100010
struct node
{
 int a,b,c;
}ans[MAXN];
int main() {
   int R, G;
   scanf("%d%d",&R,&G);
   int x=min(R,G);
   ,t=MAXN-;
   ; i*i<=x; ++i )
    {
       )
        {
          &&R%i==)
           {ans[s].a=i;
            ans[s].b=R/i;
            ans[s].c=G/i;
            s++;
           }
           &&R%(x/i)==)
           {
            ans[t].a=x/i;
            ans[t].b=R/(x/i);
            ans[t].c=G/(x/i);
            t--;
           }
         }
      }
   ;i>t;i--)
    printf("%d %d %d\n",ans[i].a,ans[i].b,ans[i].c);
        printf("%d %d %d\n",ans[i].a,ans[i].b,ans[i].c);
   ;
}

第二题:另类区间和

动态规划、记忆化搜索

官方题解:

Let f(n, prefix) consider all numbers in the interval [prefix·10n, (prefix+1)·10n>. The function calculates

the total contribution towards the result of n digits yet to be placed to the right of the given prefix.

To calculate f, we add a group of any digit other than the last one in prefix. For example, suppose n=4

and prefix=112. f(4, 112) considers the numbers 1120000 through 1129999. If we decide to append the

group 55 to the number, the contribution of this recursive branch is 52 + f(2, 11255).

It may seem that it takes too many recursive calls to calculate the result. However, many of these yield

the same result for different prefixes, more precisely when the entire interval considered is contained

inside [A, B]. For these cases we can memoize the result (it depends only on n). There are only

O(log B) recursive calls in which we branch without memoization.

#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long llint;

llint A, B;
llint p10[16];
llint memo[16][11];

llint intersect( int n, llint prefix ) {
   if( n < 0 ) return 0;
   llint lo = max( prefix * p10[n], A );
   llint hi = min( (prefix+1) * p10[n] - 1, B );
   if( lo > hi ) return 0;
   return hi-lo+1;
}

llint rec( int n, int prev, llint prefix ) {
   llint mini = prefix * p10[n];
   llint maxi = (prefix+1) * p10[n] - 1;
   if( mini > B || maxi < A ) return 0;
   if( mini >= A && maxi <= B && memo[n][prev] != -1 ) return memo[n][prev];
   llint ret = 0;
   for( int digit = 0; digit <= 9; ++digit ) {
      if( digit == prev ) continue;
      llint t = prefix;
      for( int k = 1; k <= n; ++k ) {
         t = t*10+digit;
         ret += digit * k * k * (intersect( n-k, t )-intersect( n-k-1, t*10+digit)) + rec( n-k, digit, t );
      }
   }

   if( mini >= A && maxi <= B ) memo[n][prev] = ret;

   return ret;
}

int main( void ) {
   scanf( "%lld%lld", &A, &B );
   p10[0] = 1;
   for( int i = 1; i <= 15; ++i ) p10[i] = p10[i-1] * 10;
   memset( memo, -1, sizeof memo );
   printf( "%lld\n", rec( 15, 10, 0 ) );
   return 0;
}

第三题:01序列

线段树

交替出现的序列才是合法的序列,题目要求最长序列的长度。我们可以用线段树来解决。

当前区间最长序列长度应该等于下面三者的最大值:

左儿子区间的最长序列、右儿子区间的最长序列、以及

左儿子的后缀与右儿子的前缀组成的序列。

所以每个节点需要保存5个值:区间最长的合法序列的长度,前缀长度,后缀长度,前缀的第一个字符,后缀的最后一个字符。

其他的我们还需要知道前缀的最后一个字符,但我们可以通过前缀长度和前缀的第一个字符推导出来,后缀的第一个字符我们也可以通过后缀的最后字符和后缀长度推导出来。

标程:(01序列)

#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

const int mxn = 1<<19;

struct node{
	int mx;
	int left, right;
	char start, end;
	int len;

} data[2*mxn];

node operator +( const node &a, const node &b ){
	node ret;
	ret.start = a.start;
	ret.end = b.end;
	ret.len = a.len + b.len;
	ret.left = a.left;
	if( a.len == a.left && a.end != b.start ) ret.left += b.left;

	ret.right = b.right;
	if( b.len == b.right && a.end != b.start ) ret.right += a.right;

	ret.mx = max( max( a.mx, b.mx ), max( ret.left, ret.right ) );
	if( a.end != b.start ) ret.mx = max( ret.mx, a.right+b.left );

	return ret;
}

int n;

void construct( int i, int lo, int hi ){
  if( hi-lo == 1 ){
    if( lo >= n ) data[i].mx = data[i].left = data[i].right = 0;
    else data[i].mx = data[i].left = data[i].right = 1;
    data[i].start = data[i].end = 'L';
    data[i].len = 1;
    return;
  }

  construct( 2*i, lo, (lo+hi)/2 );
  construct( 2*i+1, (lo+hi)/2, hi );
  data[i] = data[2*i] + data[2*i+1];
}

void change( int i ){
  i += mxn;
  if( data[i].start == 'L' ) data[i].start = 'R';
  else data[i].start = 'L';
  data[i].end = data[i].start;

  for( i /= 2; i > 0; i /= 2 )
    data[i] = data[2*i] + data[2*i+1];
}

int main(){
  int q;

  scanf( "%d %d", &n, &q );
  construct( 1, 0, mxn );

  for( ; q > 0; q-- ){
    int i;
    scanf( "%d", &i ); i--;

    change(i);
    printf( "%d\n", data[1].mx );
  }

  return 0;
}

contesthunter暑假NOIP模拟赛第一场题解的更多相关文章

  1. NOI.AC NOIP模拟赛 第一场 补记

    NOI.AC NOIP模拟赛 第一场 补记 candy 题目大意: 有两个超市,每个超市有\(n(n\le10^5)\)个糖,每个糖\(W\)元.每颗糖有一个愉悦度,其中,第一家商店中的第\(i\)颗 ...

  2. NOI.AC NOIP模拟赛 第二场 补记

    NOI.AC NOIP模拟赛 第二场 补记 palindrome 题目大意: 同[CEOI2017]Palindromic Partitions string 同[TC11326]Impossible ...

  3. nowcoder(牛客网)提高组模拟赛第一场 解题报告

    T1 中位数(二分) 这个题是一个二分(听说是上周atcoder beginner contest的D题???) 我们可以开一个数组b存a,sort然后二分b进行check(从后往前直接遍历check ...

  4. WC2019 全国模拟赛第一场 T1 题解

    由于只会T1,没法写游记,只好来写题解了... 题目链接 题目大意 给你一个数列,每次可以任取两个不相交的区间,取一次的贡献是这两个区间里所有数的最小值,求所有取法的贡献和,对 \(10^9+7\) ...

  5. nowcoder(牛客网)普及组模拟赛第一场 解题报告

    蒟蒻我可能考了一场假试 T1 绩点 这题没什么好说的,应该是只要会语言的就会做. T2 巨大的棋盘 一个模拟题吧qwq,但是要注意取模的时候先加上n或者m再取模,要不然会错的. #include< ...

  6. NOI.AC省选模拟赛第一场 T1 (树上高斯消元)

    link 很容易对于每个点列出式子 \(f_{x,y}=(f_{x,y-1}+f_{x,y}+f_{x,y+1}+f_{x+1,y})/4\)(边角转移类似,略) 这个转移是相互依赖的就gg了 不过你 ...

  7. CH Round #52 - Thinking Bear #1 (NOIP模拟赛)

    A.拆地毯 题目:http://www.contesthunter.org/contest/CH%20Round%20%2352%20-%20Thinking%20Bear%20%231%20(NOI ...

  8. CH Round #49 - Streaming #4 (NOIP模拟赛Day2)

    A.二叉树的的根 题目:http://www.contesthunter.org/contest/CH%20Round%20%2349%20-%20Streaming%20%234%20(NOIP 模 ...

  9. CH Round #48 - Streaming #3 (NOIP模拟赛Day1)

    A.数三角形 题目:http://www.contesthunter.org/contest/CH%20Round%20%2348%20-%20Streaming%20%233%20(NOIP模拟赛D ...

随机推荐

  1. NOIP2011 普及組 統計單詞數

    题目描述 一般的文本编辑器都有查找单词的功能,该功能可以快速定位特定单词在文章中的位置,有的还能统计出特定单词在文章中出现的次数. 现在,请你编程实现这一功能,具体要求是:给定一个单词,请你输出它在给 ...

  2. Vigenère 密码NOIP 2012 提高组 第一天 第一题

    题目描述 16 世纪法国外交家 Blaise de Vigenère 设计了一种多表密码加密算法――Vigenère 密 码.Vigenère 密码的加密解密算法简单易用,且破译难度比较高,曾在美国南 ...

  3. 《Java程序设计》第3周学习总结

    学号20145220<Java程序设计>第3周学习总结 教材学习内容总结 使用jave撰写程序几乎都在使用对象(Object),要产生对象必须先定义类(Class),类是对象的设计图,对象 ...

  4. IE6 7 8BUG锦集

    1.浮动元素的双倍margin 说明:这是IE6及其以下版本的一个经典的BUG,触发这个BUG产生的条件是给元素设置了浮动并且同一方向设置了margin值.来看以下代码: <style type ...

  5. HashMap的原理与实 无锁队列的实现Java HashMap的死循环 red black tree

    http://www.cnblogs.com/fornever/archive/2011/12/02/2270692.html https://zh.wikipedia.org/wiki/%E7%BA ...

  6. Wireshark-BPF过滤规则

    设置过滤规则就是让网络设备只是捕获我们感兴趣的网络数据包,如果没有设置过滤规则,即上面的 filter_app 是空字符串,那么网络设备就捕获所有类型的数据包,否则只是捕获过滤规则设置的数据包,此时过 ...

  7. lvM增减教程-转

    http://blog.jobbole.com/71858/ 逻辑卷管理LVM是一个多才多艺的硬盘系统工具.无论在Linux或者其他类似的系统,都是非常的好用.传统分区使用固定大小分区,重新调整大小十 ...

  8. 常规SQL注入脚本

    一:union报错注入 猜字段长度:order by 28 先显示位http://127.0.0.1/sql.php?cmd=-1 UNION SELECT 1,2,3,4,5,6,7,8,9 当前数 ...

  9. 怎么用CorelDRAW插入、删除与重命名页面

    在绘图之前,页面的各种设置也是一项重要的工作,本文主要讲解如何在CorelDRAW中插入.删除.重命名页面等操作.在CorelDRAW的绘图工作中,常常需要在同一文档中添加多个空白页面,删除一些无用的 ...

  10. svg如何用marker 定义一个黑色的小圆点

    <defs> <marker id="markerStartArrow" viewBox="0 0 30 30" refX="10& ...