怎么说,确实50pts垫底。可是并不是不会。。。
T1:
【题目描述】
二哥想知道在一段时期内,一共有多少个交易日。期货交易日的限定如下:
周六、周日不能交易;
元旦期间(1 月 1 日)不能交易;
五一劳动节期间(5月 1日至 3 日)不能交易;
十一国庆节期间(10月 1日至 7 日)不能交易;
没有在上述要求中提到的日期均可交易。
【输入数据】
第一行有一个整数 n,表示一共有 n 组数据。
每组数据都有一行,是两个用空格分开的日期,分别为开始日期和结束日期。
日期格式为 YYYY-MM-DD(比如 2010-11-11)。
数据保证开始日期不晚于结束日期。
【输出数据】
输出共 n 行,每行一个整数,对应于一组数据。
每组数据需要输出在指定日期区间内,共有多少个交易日。
区间的开始和结束日期也算在内(如果是交易日的话)。
【数据规模】
对于所有数据:n≤365。对于 30%的数据: 日期范围从 2010-11-23至 2012-12-21;
对于 100%的数据:日期范围从 1900-01-01至 9999-12-31;
已知 1900-01-01是星期一。
大模拟。
忘了考虑365组数据,结果直接暴力找的。。。TLE到30
#include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> #include<iostream> using namespace std; typedef long long ll; int ans,t; struct node{ int c[4]; }st,nd,now; char s[30]; char ch; int day[13]={0,31,28,31,30,31,30,31,31,30,31,30,31}; int sum[13]; void clear(){ ans=0; } node in(){ int len=strlen(s+1); int cnt=0; node ret; for(int i=1;i<=len;i++){ if(s[i]>'0'&&s[i]<='9'){ int sum=0;cnt++; while(i<=len&&s[i]>='0'&&s[i]<='9'){ sum=sum*10+s[i]-'0';i++; } ret.c[cnt]=sum; i--; } } return ret; } bool run(int x){ if((x%4==0&&x%100!=0)||(x%400==0)) return true; return false; } bool lim(node lp,node kk){ if(lp.c[1]<kk.c[1]) return true; if(lp.c[1]>kk.c[1]) return false; if(lp.c[2]<kk.c[2]) return true; if(lp.c[2]>kk.c[2]) return false; if(lp.c[3]<=kk.c[3]) return true; if(lp.c[3]>kk.c[3]) return false; return false; } int main(){ //freopen("stock.in","r",stdin); //freopen("stock.out","w",stdout); scanf("%d",&t); for(int i=1;i<=12;i++) sum[i]=sum[i-1]+day[i]; while(t--){ clear(); scanf("%s",s+1); st=in(); scanf("%s",s+1); nd=in(); int xing=1; int tot=0; for(int i=1900;i<st.c[1];i++){ if((i%4==0&&i%100!=0)||(i%400==0)){ tot+=366; } else tot+=365; } xing=1+tot%7;//has st.year's xingqi tot=0; for(int i=1;i<st.c[2];i++){ if(i==2){ if(run(st.c[1])) tot+=29; else tot+=28; } else tot+=day[i]; } xing=xing+tot%7;//has st.month's xingqi if(xing>7) xing-=7; tot=0; for(int i=1;i<st.c[3];i++){ tot++; } xing=xing+tot%7;//has st.day's xingqi if(xing>7) xing-=7; //cout<<" xing "<<xing<<endl; now=st; if(nd.c[1]-st.c[1]!=0){ node up;up.c[1]=now.c[1],up.c[2]=12,up.c[3]=31; while(lim(now,up)){ if(xing!=6&&xing!=7){ if(now.c[2]!=1||now.c[3]!=1){ if(now.c[2]!=10||now.c[3]>7){ if(now.c[2]!=5||now.c[3]>3){ ans++; } } } } xing++;if(xing==8) xing=1; now.c[3]++; if(now.c[3]>day[now.c[2]]){ if(now.c[2]==2){ if(!run(now.c[1])) { now.c[3]=1,now.c[2]++; } else if(now.c[3]==30){ now.c[3]=1,now.c[2]++; } } else { now.c[3]=1,now.c[2]++; } } if(now.c[2]>12) now.c[1]++,now.c[2]=1; } int i=now.c[1]; for(;i<nd.c[1];i++){ int tot=365+run(i); ans+=8-xing-(xing<=6)-(xing<=7); if(xing!=6&&xing!=7) ans--;//01-01 int day51=xing+(sum[4]+run(i))%7; if(day51!=6&&day51!=7) ans--; day51++;if(day51==8) day51=1; if(day51!=6&&day51!=7) ans--; day51++;if(day51==8) day51=1; if(day51!=6&&day51!=7) ans--; day51++;if(day51==8) day51=1;//05-01 ans-=5;//10-01 tot-=8-xing; ans+=5*(tot/7); int re=tot%7; //xing=1; ans+=re-(re==6); xing=re+1; } now.c[1]=i,now.c[2]=now.c[3]=1; } while(lim(now,nd)){ if(xing!=6&&xing!=7){ if(now.c[2]!=1||now.c[3]!=1){ if(now.c[2]!=10||now.c[3]>7){ if(now.c[2]!=5||now.c[3]>3){ ans++; } } } } xing++;if(xing==8) xing=1; now.c[3]++; if(now.c[3]>day[now.c[2]]){ if(now.c[2]==2){ if(!run(now.c[1])) { now.c[3]=1,now.c[2]++; } else if(now.c[3]==30){ now.c[3]=1,now.c[2]++; } } else { now.c[3]=1,now.c[2]++; } } if(now.c[2]>12) now.c[1]++,now.c[2]=1; } printf("%d\n",ans); } return 0; }
T2:
【题目描述】
Bob看见一个字符串,它包含许多不同的字符,这些字符被标记成不同的数字,但同一个字
符串中每个字符能在字符串出现最多 10 次。Bob不喜欢这个字符串,因为它包含重复段:一段长
为 x 的字符串的重复段是一个长为 2x 的字符串,且其前半个字符串与后半个字符串每个字符对
应相同。Bob 开始从该字符串中删除所有重复段,他按以下规则进行:如果可能,Bob 选择最短
的重复段,如果它不唯一,他选择最左边的那个,并删除该重复段的左半边和它左侧的所有东西。
现在给出 Bob看见的字符串,找出其被 Bob按上述规则删除所有重复子串之后的样子。
【输入】
输入文件第一行包含整数 n,表示字符串的长度。
下面一行包含 n 个由空格隔开的在 0 到 10^9范围内的数字,数字表示字符串中的字符。
数据保证每个字符在字符串中最多出现 10 次。
【输出】
输出文件的第一行包含 Bob删除后遗留的子串的长度。
第二行输出 Bob 按照上述方式删除所有重复段后遗留的子串(每个字符由一个空格隔开)。
我机智地在不需要至少10个字符的这个条件下,写出了优于常人的正解。。。
然而,题目要求是:
1.输出剩余长度
2.输出剩余的字符串。
说!!
为什么忘了第一个???
真·AC100变爆零
#include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> #include<iostream> #include<map> using namespace std; typedef long long ll; const int N=100000+5; int n; int a[N]; map<int,int>mp; int nxt[N],b[N]; int tot; int R; int main(){ //freopen("dor.in","r",stdin); //freopen("dor.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&a[i]); for(int j=n;j>=1;j--){ nxt[j]=mp[a[j]]; if(nxt[j]) b[j]=nxt[j]-j; mp[a[j]]=j; } for(int i=1;i<=n;i++){ if(b[i]==0) continue; int cnt=0,v=b[i]; while(i<=n&&b[i]==v&&cnt<v){ cnt++;i++; } i--; if(cnt==v){ R=max(R,i); } } printf("%d\n",n-(R+1)+1); for(int i=R+1;i<=n;i++){ printf("%d ",a[i]); } return 0; }
T3:
【问题描述】
为了绿化乡村,H村积极响应号召,开始种树了。
H村里有n幢房屋,这些屋子的排列顺序很有特点,在一条直线上。于是方便起见,我们给它
们标上1~n。树就种在房子前面的空地上。
同时,村民们向村长提出了m个意见,每个意见都是按如下格式:希望第Li个房子到第Ri个房
子的房前至少有Ci棵树。
因为每个房屋前的空地面积有限,所以每个房屋前最多只能种Ki棵树。
村长希望在满足村民全部要求的同时,种最少的树以节约资金。现在请你编程帮助村长解决
这个问题。
【数据范围】
对于30%的数据, 0<n≤100,0<m≤100,Ki=1;
对于50%的数据, 0<n≤2000,0<m≤5000,0<Ki≤100;
对于70%的数据, 0<n≤50000,0<m≤100000,0<Ki≤1000;
对于100%的数据,0<n≤500000,0<m≤500000,0<Ki≤5000。
其实很裸的差分约束了。
但是,由于对于这种类型题目,和差分约束实在不熟悉。结果没有想出来。
对于ai-bi>=ci这种,而且又有区间,而且对于区间和有一个限制
直接前缀和做差啊!!全都有了!!
就是想不到?!?!
差分约束一般都是前缀和做差。——ywy_c_asm
确实,反正是没做过其他的。。。
然后对于差分约束的理解:
1.如果跑最短路,那么得到的dis是<=源点到每个点距离L的最大解。
为什么?首先最短路,一定小于等于L,其次,由于刚好满足最短的时候,本来可以人为再小一些的,也可能满足条件。
但是,连得边权就是这样,怎么会再少一些距离呢?
所以,刚好满足最短的时候,就停止了,所以一定是所有合法解中最大的一个。
2.如果跑最长路,得到的是>=L的最小解。
证明同理。
这个题,一看,sum[i]>=0而且要最小。
直接列式子,然后spfa最长路即可。
(dij不行,有负权边)
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=500000+5; const int inf=0x3f3f3f3f; void rd(int &x){ char ch; while(!isdigit(ch=getchar())); for(x=(ch^'0');isdigit(ch=getchar());x=x*10+(ch^'0')); } struct node{ int nxt,to; int val; }e[4*N]; int hd[N],cnt; int n,m; void add(int x,int y,int z){ e[++cnt].nxt=hd[x]; e[cnt].to=y; e[cnt].val=z; hd[x]=cnt; } int dis[N]; int q[N*10],l,r; bool vis[N]; void spfa(){ for(int i=0;i<=n;i++) dis[i]=-inf; dis[n+1]=0; l=1,r=0; q[++r]=n+1; vis[n+1]=1; while(l<=r){ int x=q[l++]; vis[x]=0; //cout<<x<<endl; for(int i=hd[x];i;i=e[i].nxt){ int y=e[i].to; if(dis[y]<dis[x]+e[i].val){ dis[y]=dis[x]+e[i].val; if(!vis[y]){ vis[y]=1; q[++r]=y; } } } } } int main(){ rd(n);rd(m); int k,c; int l,r; for(int i=1;i<=n;i++){ //scanf("%lld",&k); rd(k); add(i,i-1,-k); add(i-1,i,0); add(n+1,i,0); } add(n+1,0,0); for(int i=1;i<=m;i++){ //scanf("%d%d%lld",&l,&r,&c); rd(l);rd(r);rd(c); add(l-1,r,c); } spfa(); printf("%d",dis[n]); return 0; }