[Balkan2007]Dream

[Balkan2007]Dream

Time Limit:10000MS Memory Limit:165536K
Total Submit:3 Accepted:2
Case Time Limit:1000MS

Description

给出N行M列的数字矩阵.
从第一行的数列中选一个数字,从最后一行的数列中选一个数字.
从其它的行中,每行取一到两个数.
将取出来的数字相乘,希望其可以被K整除.
你只需要输出结果Mod L的值.

Input

第一行给出N,M
第二行给出K,L
下面有N行M列,用于描述数字矩阵
其值在[1,1000000]各不相同.

N在[3,200]
M在[3,10000]
K在[2,200000]
L在[2,30000]

Output

取法总数Mod L

Sample Input

Sample Output

Hint

以下为样例的12种取法.
5 2 1
2 1 2
3 7 4
Pic. 1

5 2 1
2 1 2
3 7 4
Pic. 2

5 2 1
2 1 2
3 7 4
Pic. 3

5 2 1
2 1 2
3 7 4
Pic. 4

5 2 1
2 1 2
3 7 4
Pic. 5

5 2 1
2 1 2
3 7 4
Pic. 6

5 2 1
2 1 2
3 7 4
Pic. 7

5 2 1
2 1 2
3 7 4
Pic. 8

5 2 1
2 1 2
3 7 4
Pic. 9

5 2 1
2 1 2
3 7 4
Pic. 10

5 2 1
2 1 2
3 7 4
Pic. 11

5 2 1
2 1 2
3 7 4
Pic. 12

Source
好吧这题不算难。。但是挺有意思的。。一开始我想的是记录对K的每种余数有多少个,但那样显然太SB了。。。。后来我感觉这样很浪费啊。。实际上当前唯一有用的信息是与K的最大公约数!!。。。而K的约数不会超过300个(还记得反素数那个题目么。。特意算了下)。。所以毫无压力的就可以A掉了。。。需要与处理一下两个约数相乘之后与K的最大公约数。。。。以及每个数与K的最大公约数(类似筛法的搞)。。。
另外最近一直在看TopCoder SRM Level 3的题目。。有了不少感触啊。。有时间写个表格饿囧。。
Code:

#include<cstdio>#include<algorithm>#include<iostream>#define rep(i,n) for(int i=0;i<n;i++)using namespace std;const int maxn=200,maxm=10000,maxk=200000,maxw=1000000,maxs=300;typedef long long ll;int mod,k,n,m,Div[maxw+1],L[maxs],dn=0,Next[maxs][maxs];inline void Add(int&x,int c){x+=c;x%=mod;}inline void Mult(int&x,int c){x*=c;x%=mod;}int Dp[2][maxs],c1[maxs],c2[maxs];int main(){ //freopen("in","r",stdin); scanf("%d%d%d%d",&n,&m,&k,&mod); for(int i=1;i<=k;i++)if(k%i==0)L[dn++]=i; rep(i,dn)rep(j,dn) for(int k=dn-1;k>=0;k–)if(ll(L[i])*L[j]%L[k]==0) { Next[i][j]=k;break; } rep(i,dn) { int x=L[i]; for(int j=x;j<=maxw;j+=x)Div[j]=i; } int x,now=0,old=1; rep(i,m)scanf("%d",&x),Add(Dp[now][Div[x]],1); rep(i,n-1) { swap(now,old);memset(Dp[now],0,sizeof Dp[now]); memset(c1,0,sizeof c1); memset(c2,0,sizeof c2); rep(i,m)scanf("%d",&x),Add(c1[Div[x]],1); memcpy(c2,c1,sizeof c1); if(i!=n-2) rep(a,dn)rep(b,a+1) if(a!=b)Add(c2[Next[a][b]],c1[a]*c1[b]*2); else Add(c2[Next[a][b]],c1[a]*(c1[a]-1)); rep(a,dn)rep(b,dn) Add(Dp[now][Next[a][b]],Dp[old][a]*c2[b]); } printf("%dn",Dp[now][dn-1]);}123 312 1005 2 12 1 23 7 4

[HNOI2008]神奇的国度

[HNOI2008]神奇的国度

Time Limit:20000MS Memory Limit:165536K
Total Submit:150 Accepted:41
Case Time Limit:5000MS

Description

K国是一个热衷三角形的国度,连人的交往也只喜欢三角原则.他们认为三角关系:即AB相互认识,BC相互认识,CA相互认识,是简洁高效的.为了巩固三角关系,K国禁止四边关系,五边关系等等的存在.所谓N边关系,是指N个人
A1A2…An之间仅存在N对认识关系:(A1A2)(A2A3)…(AnA1),而没有其它认识关系.比如四边关系指ABCD四个人
AB,BC,CD,DA相互认识,而AC,BD不认识.全民比赛时,为了防止做弊,规定任意一对相互认识的人不得在一队,国王相知道,最少可以分多少支队。

Input

第一行两个整数N,M。1<=N<=10000,1<=M<=1000000.表示有N个人,M对认识关系.
接下来M行每行输入一对朋友

Output

输出一个整数,最少可以分多少队

Sample Input

Sample Output

Hint

一种方案(1,3)(2)(4)

Source
哎。。总算差不多做完HNOI2008了。。我真是个傻叉啊。。
这题当时就把我震惊了。。一点思路都没有。。最小染色数不是NP问题么?
后来看了
AekdyCoin神牛的题解才明白这是个弦图。。所以有专门的算法。。
神牛已经说的很清楚了。。Orz!!!!!!!
Code:
#include <vector>

#include <cstdio>
#include <iostream>
#define rep(i,n) for(int i=0;i<n;i++)
#define pb push_back
#define tr(e,x) for(it e=x.begin();e!=x.end();e++)
const int maxn=10000+10;
using namespace std;
typedef vector<int>::iterator it;
int n,m,cnt[maxn]={},c[maxn]={},hash[maxn]={};
bool v[maxn]={};
vector<int> E[maxn],ord;
int main()
{
    //freopen("in","r",stdin);
    scanf("%d%d",&n,&m);int s,t;
    while(m–)scanf("%d%d",&s,&t),–s,–t,E[s].pb(t),E[t].pb(s);
    rep(i,n)
    {
        int max=-1,t;
        rep(j,n)if(!v[j]&&cnt[j]>max)max=cnt[j],t=j;
        v[t]=true;tr(e,E[t])cnt[*e]++;
        ord.pb(t);
    }
    c[ord[0]]=1;
    for(int id=1;id<=n-1;id++)
    {
        int t=ord[id];
        tr(e,E[t])hash]=id;
        rep(i,n)if(hash[i+1]!=id){c[t]=i+1;break;}
    }
    int ans=0;rep(i,n)ans>?=c[i];
    printf("%dn",ans);
}

34 51 21 42 42 33 4

SRM 472

悲剧了。。第一题是水题。。写了个暴力DP找规律。。
然后脑子抽筋了跳过第二题去做第三题。算法想出来了。。。但是脑残一直搞错了些东西。。最后没时间写些special case的检查了。。悲剧啊。。。
卧槽。。我这个水平也太烂了。。。4个月白过了囧。。。

C++里面一点小技巧。。。

额。。神牛别骂我火星额囧。。只是最近看到一些C++中比较神奇的东西。。。
#define
其实define的作用大得惊人。。可以大大简化代码甚至代替template
1. #x
先看下这个代码
#define Debug(x) cout<<#x<<"="<<(x)<<endl;
int i=5;Debug(i);
可能你不知道#x是什么意思,不过运行一下啊就会发现结果是i=5说明#x就是带进去的这个东西的字符串形式。。运用这个形式,可以方便的做一个像上面那个那个Debug的函数,像我这样从来不调试的NC来说,真是福音啊。。
2.##x
一样,先看下这个代码
#define D(x) m##x
int D(x)=0;cout<<m1<<endl;
结果能输出并且就是0.。
也就是说##x就是把它看成原来的一段字符(不是字符串)接在后面。。
运用这个可以很方便的声明和初始化多个变量。。。
#define D(x) int m##x=0
D(0);D(1);D(2);D(3);D(4);D(5);D(6);D(7);
3.多行
#define是可以多行的。只要在除了最后一行的每一行后面加一个就可以了。。
比如
#define Swap(T,x,y)
{
    T tmp=x;x=y;y=tmp;
}
int a=0,b=1;Swap(int,a,b);Debug(a);Debug(b);
这样就可以甚至拿来代替template。。这种东西在某些大量使用的代码段中可以大大方便Coder
还有一些很强大的符号
a<?b <=> min(a,b)
a>?b <=>max(a,b)
a<?=b <=> a=min(a,b)
a>?=b <=> a=max(a,b)
另外我快被Java搞死了。。这玩意太精细了。。写起来累死人。。。晚上就要有TopCoder比赛了。。我还是用C++算了。。.
最诡异的是algorithm这个库居然能够加快程序的速度?????见鬼啊。。

[Ceoi2006]Queue

[Ceoi2006]Queue

Time Limit:10000MS Memory Limit:65536K
Total Submit:17 Accepted:12
Case Time Limit:1000MS

Description

If you are an average football fan, you probably know that obtaining tickets for this year’s World Cup in Germany was an impossible task. Greedy organizers and football federations grabbed the majority or available tickets and divided them among sponsors, friends and family members. As a result, jet setters have flooded the venues, while die-hard fans sit at home enjoying the games between advertisements featuring crappy beer and sugar-free chewing gum.
A couple of tickets are left for the final game and a huge queue has formed in front of the ticker office. As fans were arriving, they were labeled with successive integers. The first person in queue was labeled with number one, the second with number two, etc.
Since the fans arrived the night before, they had to wait for a long time before the ticket counter was open and, naturally, some of them had to use the restroom. Each time a person needs to use the restroom, he/she steps out of the queue and, and, after completing the task, steps back into the queue, though not necessarily at the same position as before. Since there is only one restroom available no person leaves the queue before the previous person has returned (hence, at any moment there is at most one person missing from the queue).
During the course of the night, a total of N restroom visits have occurred. Each visit is described by two positive integers A and B, denoting that the person labeled A stepped out of the queue and the stepped back into the queue immediately in front of the person labeled B. Now that all the visits have completed, the officials have to answer a series of questions. Each question is either of the form ‘P X’, asking for the position lf the person labeled X, or of the form ‘L X’, asking for the label of the person at position X.
The first person in queue is considered to be at position one, the second at position two, etc.
Write a program that, given the description of the visits and a number of questions, answers all of the questions.

一开始将一列人按编号从1开始顺序排列,然后进行N次操作,每次将编号为A的人拿出,放在编号为B的人前面,所有操作进行完后有Q个问题,询问编号为X的人的位置,或者询问在X号位置上的人的编号。

Input

The first line of input contains an integer N(2 ≤ N ≤ 50 000)- the total number of restroom visits.
Each of the following N lines contains two different integers A and B (1 ≤ A, B ≤ 109), describing one restroom visit. The nest line contains an integer Q (1 ≤ Q ≤ 50 000) – the total number of questions.
Each of the following Q lines contains a single character (either the uppercase letter ‘P’ or the uppercase letter ‘L’) and an integer X (1≤ X ≤109) , describing one question.

Output

The output should consist of a total of Q lines.
The ith line or output should contain a single integer R – the answer to the ith question.
If the corresponding question is of the form ‘P Xi’ then R should be the final position of the person labeled Xi.
If the corresponding question is of the form ‘L Xi’ then R should be the label of the person at position Xi.

Grading
Partial credit is awarded for incorrect solutions that correctly answer all questions of one type. If all questions of the form ‘P X’ are answered correctly or if all questions of the form ‘L X’ are answered correctly, you will receive 50% of the corresponding test case.
In order to receive partial credit, the output should be formatted according to the specifications. Therefore, even if you choose to answer only one type of questions, you should still produce output for all questions of the other type.

Sample Input

Sample Output

Source
额。。。这题实际上只要注意到一种技术叫实时离散化,由于范围很大而n很小,很多块都是连续的。。那么信息可以忽略,只需要记录一些转角地方的点前驱和后继就可以了。。然后一遍扫描过去就可以得出所有的答案了。。我的程序鬼速到了极点。。囧啊。。
Code:
#include <vector>

#include <algorithm>
#include <utility>
#include <cstdio>
#include <map>
#define rep(i,n) for(int i=0;i<n;i++)
#define pb push_back
#define All(x) x.begin(),x.end()
const int inf=2e9,maxn=50000+10;
using namespace std;
map<int,int> Pre,Next;
int n,m,Ans[maxn];
int pre(int x){return Pre.count(x)?Pre[x]:x-1;}
int next(int x){return Next.count(x)?Next[x]:x+1;}
typedef pair<int,int> ii;
typedef vector<ii>::iterator it;
vector<ii> L,P;
void init()
{
    scanf("%d",&n);int a,b;
    rep(i,n)
    {
        scanf("%d%d",&a,&b);
        Next[pre(a)]=next(a);
        Pre[next(a)]=pre(a);
        Next[pre(b)]=a;
        Pre[a]=pre(b);
        Next[a]=b;
        Pre[b]=a;
    }
    Next[inf]=inf+1;
    char c;scanf("%d",&m);
    rep(i,m)
    {
        scanf(" %c %d",&c,&a);
        if(c==’P’)P.pb(ii(a,i));
        else L.pb(ii(a,i));
    }
    L.pb(ii(inf,m));P.pb(ii(inf,m));
    sort(All(L));sort(All(P));
}
void Solve()
{
    int now=0,Min,pos=0;
    while(now<inf)
    {
        int a=Next.lower_bound(now)->first-now;
        int b=lower_bound(All(L),ii(pos,0))->first-pos;
        int c=lower_bound(All(P),ii(now,0))->first-now;
        Min=a<?b<?c;
        now+=Min;pos+=Min;
        if(Min==b)
        {
            it l=lower_bound(All(L),ii(pos,0)),r=lower_bound(All(L),ii(pos+1,0));
            for(it i=l;i!=r;i++)
                Ans[i->second]=now;
        }
        if(Min==c)
        {
            it l=lower_bound(All(P),ii(now,0)),r=lower_bound(All(P),ii(now+1,0));
            for(it i=l;i!=r;i++)
                Ans[i->second]=pos;
        }
        now=next(now);
        ++pos;
    }
    rep(i,m)printf("%dn",Ans[i]);
}
int main()
{
    init();Solve();
}

103154411000009999926 39 68L 1L 2L 3L 4P 1P 2P 3P 4Output12961256Input57 22 79 710 110005 99959L 1P 2L 2P 7L 7P 9P 10P 99999P 100000

[JSOI2008]最小生成树计数

[JSOI2008]最小生成树计数

Time Limit:1000MS Memory Limit:165536K
Total Submit:100 Accepted:38

Description

现在给出了一个简单无向加权图。你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树。(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的)。由于不同的最小生成树可能很多,所以你只需要输出方案数对31011的模就可以了。

Input

第一行包含两个数,n和m,其中1<=n<=100; 1<=m<=1000; 表示该无向图的节点数和边数。每个节点用1~n的整数编号。
接下来的m行,每行包含两个整数:a, b, c,表示节点a, b之间的边的权值为c,其中1<=c<=1,000,000,000。数据保证不会出现自回边和重边。
注意:具有相同权值的边不会超过10条。

Output

输出不同的最小生成树有多少个。你只需要输出数量对31011的模就可以了。

Sample Input

Sample Output

Source
这题是老题了。。本来想A掉爽一下的,结果WA半天,最后发现还可能有无生成树的情况囧。。。
。。算法的话很显然对于所有一组权值相同的边,它们以最大数量加入之后,造成的连通性是一样的,那么从小到大算出每一组边,乘起来就OK了。。
如果数据大一点的话只好用矩阵来算答案了。。不过这里范围这么小暴力就OK了。。。
Code:
#include <vector>

#include <iostream>
#include <map>
#include <utility>
#define rep(i,n) for(int i=0;i<n;i++)
#define pb push_back
const int mod=31011,maxn=100,maxm=1000;
using namespace std;
typedef pair<int,int> ii;
struct UF
{
    int F[maxn];
    void clear(){rep(i,maxn)F[i]=i;}
    int find(int x)
    {
        if(F[x]==x)return x;
        return F[x]=find(F[x]);
    }
    bool Union(int i,int j)
    {
        i=find(i);j=find(j);
        return F[i]=j,i!=j;
    }
    UF& operator=(const UF&u)
    {
        memcpy(F,u.F,sizeof(F));
        return *this;
    }
};
int n,m,ans=1,get,ret;
typedef map<int,vector<ii> >::iterator mit;
map<int,vector<ii> > M;
UF All,Link;
vector<ii> now;
void Dfs(int p,int c)
{
    if(p==now.size())
    {
        if(c==get)ret++;
        return;
    }
    ii t=now[p];UF tmp=Link;
    if(Link.Union(t.first,t.second))Dfs(p+1,c+1);
    Link=tmp;
    Dfs(p+1,c);
}
int main()
{
    cin>>n>>m;int s,t,c;
    rep(i,m)
    {
        cin>>s>>t>>c;s–;t–;
        M.pb(ii(s,t));
    }
    All.clear();s=0;
    for(mit i=M.begin();i!=M.end();i++)
    {
        now=i->second;Link=All;get=0;ret=0;
        rep(j,now.size())get+=All.Union(now[j].first,now[j].second);
        Dfs(0,0);ans*=ret;ans%=mod;s+=get;
    }
    if(s<n-1)cout<<0<<endl;
    else cout<<ans<<endl;
}

84 61 2 11 3 11 4 12 3 22 4 13 4 1

510. Distinct Substrings

给你一个N,让你求有恰有N个不同字串的,尽可能短的,如有多个就字典序最小的那个的字符串。。。
我感觉没有任何思路,只能暴搜。。
肯定要减枝,就是估计一个当前以当前字符串为前缀的最大可能的不同子串数。。
我不知道对不对,我是在后面defghijk这么加上去再算不同字串数的。。
计算不同字串数的话题目中也说是标准的SA问题,但我直接用Set了。。
Code:

#include<cstring>#include<iostream>#include<string>#include<cstdlib>#include<set>#define Rep(i,n) for(int i=0;i<n;i++)using namespace std;int n;string C;int Get(const string&a){ set<string> S;int n=a.size(); for(int i=0;i<n;i++) for(int j=1;i+j<=n;j++) S.insert(a.substr(i,j)); return S.size();}int Cal(int p,char u){ for(int i=p;i<C.size();i++) C[i]=++u; return Get(C);}void Dfs(int p,char u){ int N=Cal(p,u); if(N<n)return; if(p==C.size()) { if(N==n) { cout<<C<<endl; exit(0); } return; } for(char a=’a’;a<=u;a++) { C[p]=a; Dfs(p+1,u); } if(u<‘z’){C[p]=++u;Dfs(p+1,u);}}int main(){ cin>>n; for(int i=1;;i++) { C.resize(i); Dfs(0,’a’-1); }}

SGU 505. Prefixes and suffixes

就是给你一大堆字符串,然后每次询问以一个给定串为前缀,
一个给定串为后缀的字符串有几个?
我是一直没有思路的,但是在做出网易比赛的拿到有道搜索框之后
我就已经知道算法了。。但是
一直WA,今天才发现是犯了个SB错误囧啊。。。
是这样的,将所有字符串排序,由那题我明白了所有由某个前缀的字符串是一个区间,
然后将所有字符串
全部反过来排序,那么由某个后缀的字符串也是一个区间,把这些字符串都标上其在
第一遍排序中的排名。。那么问题就成了,在[a,b]中,[l,r]之间的数有几个。。
那么由两种办法,一种是在线算法,就是建个线段树,那么是LogN^2的。。
另一种就是离线算法,只需要一个树状数组就OK了。。。
鉴于第一个可能TLE。。所以我用了离线算法。。编写上需要注意一些东西。。
我发现关于string的话,cin还是蛮快的。。
Code:
include<string>
#include<algorithm>
#include<iostream>
#include<vector>
#include<cstring>
#include<cstdio>
#define pb push_back
#define Rep(i,n) for(int i=0;i<n;i++)
#define All(x) x.begin(),x.end()
#define tr(e,x) for(typeof(x.begin()) e=x.begin();e!=x.end();e++)
using namespace std;
const int maxn=100000,maxm=100000;
string S[maxn],R[maxn];
int n,m,Ans[maxm]={},A[maxn];
struct Data
{
    int l,r,num,d;
    Data(int _l,int _r,int _num,int _d):l(_l),r(_r),num(_num),d(_d){}
};
vector<Data> E[maxn];
bool AsPrefix(const string&str,const string&prefix)
{
    if(str.size()<prefix.size()||str.substr(0,prefix.size())!=prefix)
        return false;
    return true;
}
void get(string S[maxn],string pre,int&l,int&r)
{
    l=lower_bound(S,S+n,pre)-S;
    pre[pre.size()-1]++;
    r=lower_bound(S,S+n,pre)-S;
}
struct TreeArray
{
    int H[maxn+10];
    TreeArray(){memset(H,0,sizeof(H));}
    void Add(int l,int d)
    {
        l++;
        for(;l<=n;l+=(l&-l))
            H[l]+=d;
    }
    int operator[](int l)
    {
        l++;int ret=0;
        for(;l>0;l-=(l&-l))
            ret+=H[l];
        return ret;
    }
}T;
int main()
{
    //freopen("in","r",stdin);
    cin>>n;Rep(i,n)cin>>S[i],R[i]=S[i],reverse(All(R[i]));
    sort(S,S+n);sort(R,R+n);
    Rep(i,n)
    {
        string tmp=R[i];reverse(All(tmp));
        A[i]=lower_bound(S,S+n,tmp)-S;
    }
    cin>>m;string Pre,Suf;
    Rep(i,m)
    {
        cin>>Pre>>Suf;
        int l,r,a,b;
        get(S,Pre,l,r);
        if(l==r)continue;
        reverse(All(Suf));
        get(R,Suf,a,b);
        if(a==b)continue;
        E[b-1].pb(Data(l,r-1,i,1));
        if(a)E[a-1].pb(Data(l,r-1,i,-1));
    }
    Rep(i,n)
    {
        T.Add(A[i],1);
        tr(e,E[i])Ans[e->num]+=(T[e->r]-T[e->l-1])*e->d;
    }
    Rep(i,m)printf("%dn",Ans[i]);
}

[SDOI2009]SuperGCD

[SDOI2009]SuperGCD

Time Limit:4000MS Memory Limit:65536K
Total Submit:34 Accepted:6
Case Time Limit:1000MS

Description

Sheng bill有着惊人的心算能力,甚至能用大脑计算出两个巨大的数的GCD(最大公约
数)!因此他经常和别人比赛计算GCD。有一天Sheng bill很嚣张地找到了你,并要求和你比
赛,但是输给Sheng bill岂不是很丢脸!所以你决定写一个程序来教训他。

Input

共两行:
第一行:一个数A。
第二行:一个数B。

Output

一行,表示A和B的最大公约数。

Sample Input

Sample Output

Hint

对于20%的数据,0 < A , B ≤ 10 ^ 18。
对于100%的数据,0 < A , B ≤ 10 ^ 10000。

Source

Day1
总算AC了这题,感谢GCD。。。
然后是算法。。。TMD八中OJ居然没有Java。。。。只好自己写高精度,算法是这样的。。
设这两个数是A,B
那么若2|A和B (A,B)=2(A/2,B/2)。。
若2|A且2不整除B, (A,B)=(A/2,B)..
若A和B都是奇数,设A<B,(A,B)=(A,B-A)…
关键是一般的高精度超时很严重啊。。
于是压位,我压了10位。。结果因为Long Long的问题WA了几次。。。
然后把所有的2放在一起乘。。。
就很快了。。。
Orz。sevenk神牛。。
Code:

#include<cstdio>#include<cstring>#include<iostream>#define Rep(i,n) for(int i=0;i<n;i++)using namespace std;typedef unsigned long long ull;const int maxn=10000+10,L=10;const ull m=1e10;char C[maxn+10];ull P[L];struct BigInt{ ull H[maxn/L+1];int l; BigInt() { memset(H,0,sizeof(H));l=0; } void divide() { ull d=0; for(int i=l;i>=0;i–) { d*=m;d+=H[i]; H[i]=d/2;d%=2; } while(l&&!H[l])l–; } int mod() { return H[0]%2; } void operator*=(int x) { ull d=0; for(int i=0;i<=l;i++) { d+=H[i]*x;H[i]=d%m; d/=m; } while(d)H[++l]=d%m,d/=m; } void operator-=(const BigInt&o) { ull d=0; for(int i=0;i<=l;i++) { H[i]-=d; if(H[i]<o.H[i])H[i]+=m,d=1; else d=0; H[i]-=o.H[i]; } while(l&&!H[l])l–; } void ReadIn() { memset(C,0,sizeof(C)); scanf("%s",C);int s=0;l=0;ull a=0; for(int i=strlen(C)-1;i>=0;i–) { a+=(C[i]-‘0’)*P[s++]; if(s==L)H[l++]=a,s=0,a=0; } if(!s)l–;else H[l]=a; } void Print() { printf("%I64d",H[l]); for(int i=l-1;i>=0;i–)printf("%010I64d",H[i]); } bool operator<(const BigInt&o)const { if(l!=o.l)return l<o.l; for(int i=l;i>=0;i–) { if(H[i]<o.H[i])return true; if(H[i]>o.H[i])return false; } } bool iszero()const{return l==0&&H[l]==0;}}A[2];int main(){ freopen("in","r",stdin); P[0]=1;Rep(i,L-1)P[i+1]=P[i]*10; A[0].ReadIn();A[1].ReadIn(); int a=0,b=1,c=0; while(true) { if(A[b]<A[a])a^=b^=a^=b; //A[a].Print();printf(",");A[b].Print(); //puts(""); if(A[a].iszero()) { while(c>=16)A[b]*=(1<<16),c-=16; while(c–)A[b]*=2; A[b].Print(); break; } int i=A[a].mod(),j=A[b].mod(); if(!i)A[a].divide(); if(!j)A[b].divide(); if(!i&&!j)c++; if(i&&j)A[b]-=A[a]; }}61254

网易有道资格赛1-最大和子序列

我个NC。。这道题代码量实际上很小而且也不是很triky。。比赛的时候我居然悲剧囧死了。。。。
就是原来的算法,首先由于每个都是非空的那么特判一下正数小于等于2个情况(此时显然取最大的两个)。。然后先算没有跨越环的,设L[x]表示1-x的最大子序列长度,R[x]表示x-n的最大子序列长度,答案很显然就是Max(L[x]+R[x+1])。。。然后如果跨越环了,那么它的对偶问题就是不选的那些肯定不跨越环,一样的DP可以算出来(为了方便把所有值取负就OK了。。)。。两个中的最大值就是答案了。。。。
Code:
#include<cstdio>#include<algorithm>#define rep(i,n) for(int i=0;i<n;i++)using namespace std;const int maxn=50000+10,inf=~0U>>1;int t,n,A[maxn],L[maxn],R[maxn];int Cal(){ L[0]=0; for(int i=1;i<=n;i++) L[i]=max(L[i-1],0)+A[i]; R[n+1]=0; for(int i=n;i>=1;i–) R[i]=max(R[i+1],0)+A[i]; for(int i=1;i<=n;i++)L[i]=max(L[i],L[i-1]); for(int i=n;i>=1;i–)R[i]=max(R[i],R[i+1]); int ans=-inf; for(int i=1;i<=n;i++)ans=max(ans,L[i]+R[i+1]); return ans;}void Solve(){ scanf("%d",&n);int z=0,s=0,a=-inf,b=-inf; rep(i,n)scanf("%d",A+i+1),z+=A[i+1]>0,s+=A[i+1]; if(z<=2) { rep(i,n) { if(A[i+1]>b)b=A[i+1]; if(a<b)swap(a,b); } printf("%dn",a+b); return; } int ans=Cal(); rep(i,n)A[i+1]=-A[i+1]; ans=max(ans,s+Cal()); printf("%dn",ans);}int main(){ //freopen("in","r",stdin); int t;scanf("%d",&t); rep(i,t)Solve();}