NOIP模拟题 2016.11.1 [模拟] [贪心] [杂题]

T1:
题意: 模拟祖玛游戏。。。
没有必要用链表,因为找第几位的时候也是要O(n)走一遍的,不如直接平移。
注意串为空!!
虽然题目说了一开始串中没有可以消除的,但是数据还是有。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<climits>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smax(x,tmp) x=max((x),(tmp))
#define smin(x,tmp) x=min((x),(tmp))
#define maxx(x1,x2,x3) max(max(x1,x2),x3)
#define minn(x1,x2,x3) min(min(x1,x2),x3)
const int INF=0x3f3f3f3f;
const int maxn = 2005;
inline int idx(char ch) { return ch - 'A' + 1; }
struct Node
{
    int pre,nxt;
    int val;
}node[maxn];
int maxnode;
#define pre(x) node[x].pre
#define nxt(x) node[x].nxt
#define val(x) node[x].val
int _begin,_end;
queue <int> que;
inline int require()
{
    int root;
    if(!que.empty()) root=que.front(),que.pop();
    else root = ++maxnode;
    return root;
}
inline void recycle(int root)
{
    pre(root)=nxt(root)=0;
    val(root)=0;
    que.push(root);
}
char s[maxn];
int T;
void init()
{
    scanf("%s",s);
    if(s[0]>='0' && s[0]<='9')
    {
        sscanf(s,"%d",&T);
        return;
    }
    int lens = strlen(s);
    for(int i=3;i<lens+3;i++)
    {
        int d = idx(s[i-3]);
        pre(i) = i-1;
        nxt(i) = i+1;
        val(i) = d;
    }
    _begin=1; _end=2; maxnode=lens+2;
    pre(3)=_begin; nxt(maxnode)=_end;
    nxt(_begin)=3; pre(_end)=maxnode;
}
int find(int rank)
{
    int root = _begin;
    int tot = 0;
    while(tot < rank) root=nxt(root),tot++;
    return root;
}
void update(int root)
{
    if(root == _begin || root == _end) return;
    int t1=0,t2=0;
    int x = root;
    while(val(pre(x)) == val(root)) x = pre(x), t1++;
    int y = root;
    while(val(nxt(y)) == val(root)) y = nxt(y), t2++;
    if(t1+t2+1<3) return;
    x = root; y = nxt(root);
    int d = val(root);
    while(val(x) == d) x=pre(x),recycle(nxt(x));
    while(val(y) == d) y=nxt(y),recycle(pre(y));
    nxt(x)=y; pre(y)=x;
    update(x);
}
void insert(int pos,int d)
{
    int t1 = find(pos);
    int t2 = nxt(t1);
    int now = require();
    pre(now)=t1; nxt(now)=t2;
    nxt(t1)=now; pre(t2)=now;
    val(now) = d;
    update(now);
}
void print()
{
    int root = nxt(_begin);
    if(root == _end)
    {
        putchar('-');
        return;
    }
    while(root ^ _end)
    {
        putchar(val(root)+'A'-1);
        root = nxt(root);
    }
}
void work()
{
    if(!T) scanf("%d",&T);
    while(T--)
    {
        int pos;
        char ch;
        scanf("%d %c",&pos,&ch);
        insert(pos,idx(ch));
        print();
        putchar('\n');
    }
}
int main()
{
    freopen("hao.in","r",stdin);
    freopen("hao.out","w",stdout);
    init();
    work();
    return 0;
}

T2:
题意:给一个a[],用栈输出字典序最大的排列。
贪心,每次取a中最大元素和栈顶元素比较即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<climits>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smax(x,tmp) x=max((x),(tmp))
#define smin(x,tmp) x=min((x),(tmp))
#define maxx(x1,x2,x3) max(max(x1,x2),x3)
#define minn(x1,x2,x3) min(min(x1,x2),x3)
template <class T> inline void read(T &x)
{
    x = 0;
    T flag = 1;
    char ch = (char)getchar();
    while(ch<'0' || ch>'9')
    {
        if(ch == '-') flag = -1;
        ch = (char)getchar();
    }
    while(ch>='0' && ch<='9')
    {
        x = (x<<1) + (x<<3) + ch - '0';
        ch = (char)getchar();
    }
    x *= flag;
}
const int INF=0x3f3f3f3f;
const int maxn = 1000005;
bool used[maxn];
int n;
int a[maxn];
stack <int> sta;
int main()
{
    freopen("kun.in","r",stdin);
    freopen("kun.out","w",stdout);
    read(n);
    for(int i=1;i<=n;i++) read(a[i]);
    int MAX = n;
    int pos = 1;
    while(true)
    {
        while(used[MAX]) MAX--;
        if(!MAX)
        {
            while(!sta.empty()) printf("%d ",sta.top()),sta.pop();
            break;
        }
        if(sta.empty() || MAX>sta.top())
        {
            while(a[pos]^MAX) sta.push(a[pos]),used[a[pos]]=true,pos++;
            used[MAX] = true; pos++;
            printf("%d ",MAX);
        }
        else while(!sta.empty() && sta.top()>MAX) printf("%d ",sta.top()),sta.pop();
    }
    return 0;
}

T3:
题意:我们 有一个序列 ,现在他里面有三个数 1,2,2。我们从第三个数开始考虑:
1、第三个数是 2,所以我们在序列后面写 2个3,变成 1,2,2,3,3。
2、第四个数是 3,所以我们在序列后面写 3个4,变成 1,2,2,3,3,4,4,4。
那么你可以看到 ,这个序列应该是 1,2,2,3,3,4,4,4,5,5,5,6,6,6,6,…。
如果设last(x)表示x最后出现的位置,求last(last(x))。

分析:
找规律,把last(last(x))的差分序列找出来,可以发现规律,每一个数就是a[block]*i,a[block]是第一个乘数,i是从x。
分块加速处理。
a[i]大概在1300000的时候和1e9比较接近。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<climits>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smax(x,tmp) x=max((x),(tmp))
#define smin(x,tmp) x=min((x),(tmp))
#define maxx(x1,x2,x3) max(max(x1,x2),x3)
#define minn(x1,x2,x3) min(min(x1,x2),x3)
typedef long long LL;
const int mod = 1000000007;
const int N = 1400000;
const int maxn = N + 10;
int a[maxn];
LL sum[maxn],ANS[maxn];
void pre_work()
{
    a[1]=1; a[2]=a[3]=2;
    LL last = 3;
    int cur = 3;
    while(true)
    {
        for(int i=last+1;i<=last+a[cur];i++) a[i] = cur;
        last += a[cur];
        cur++;
        if(last+a[cur]>N) break;
    }
    for(int i=1;i<=N;i++) sum[i]=sum[i-1]+a[i];
    last = 0;
    for(int i=1;i<=N;i++)
    {
        LL L = last + 1;
        LL R = last + a[i];
        ANS[i] = ((LL)a[i]*((LL)L+R)/2)%mod * i %mod;
        (ANS[i] += ANS[i-1]) %=mod;
        last = R;
    }
}
void work()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n;
        scanf("%d",&n);
        int cur_i = upper_bound(sum+1,sum+N+1,n) - sum - 1;
        LL ans = ANS[cur_i];
        if(sum[cur_i]<n)
        {
            LL len = n-sum[cur_i];
            LL L = sum[cur_i] + 1;
            LL R = sum[cur_i] + len;
            cur_i++;
            ans += ((LL)len*((LL)L+R)/2)%mod * cur_i %mod;
            ans %= mod;
        }
        printf(AUTO"\n",ans);
    }
}
int main()
{
    freopen("nan.in","r",stdin);
    freopen("nan.out","w",stdout);
    pre_work();
    work();
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值