A题:
XTU 1203 A simple problem
第一次碰见这种卡常数的题。。。。。
刚开始用的long long发现还是不够,然后找了个大数模板
接下来就无限TLE,然后各种优化。。。。。
总结了下大数运算的几个优化要点
一、能不能大数的地方尽量少用大数
二、大数的数组开到够用就行,不要开太大
还有就是这道题的一个优化,暴力求前半部分的时候,可以把临界的数适当取大一点
/*
* Author: lj94093
* Created Time: 2015/5/27 星期三 下午 5:30:26
* File Name: A simple problem.cpp
*/
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
using namespace std;
#define out(x) cout<<#x<<": "<<x<<endl
const double eps(1e-8);
const int maxn=10100;
const long long inf=-1u>>1;
typedef long long ll;
ll n;
struct BigInt{
const static int mod=10000;
const static int DLEN=4;
int a[8],len;
BigInt(){
memset(a,0,sizeof(a));
len=1;
}
BigInt(ll v){
memset(a,0,sizeof(a));
len=0;
do{
a[len++]=v%mod;
v/=mod;
}while(v);
}
BigInt operator +(const BigInt &b)const{
BigInt res;
res.len=max(len,b.len);
for(int i=0;i<=res.len;i++) res.a[i]=0;
for(int i=0;i<res.len;i++) {
res.a[i] += ((i < len)?a[i]:0)+((i < b.len)?b.a[i]:0);
res.a[i+1] += res.a[i]/mod;
res.a[i] %= mod;
}
if(res.a[res.len]>0) res.len++;
return res;
}
BigInt operator *(const BigInt &b)const{
BigInt res;
for(int i=0;i<len;i++){
int up=0;
for(int j=0;j<b.len;j++){
int tmp=a[i]*b.a[j]+res.a[i+j]+up;//i位*j位,至少有i+j位
res.a[i+j]=tmp%mod;
up=tmp/mod;
}
if(up!=0){
res.a[i+b.len]=up;
}
}
res.len=len+b.len;
while(res.a[res.len-1]==0 && res.len>1) res.len--;//调整长度
return res;
}
void output(){
printf("%d",a[len-1]);
for(ll i=len-2;i>=0;i--) {
printf("%04d",a[i]);//中间的显示前导0
}
printf("\n");
}
};
int t,cas=1;
void init() {
scanf("%I64d",&n);
}
void work() {
BigInt ans=0;
//ll ans1=0;
int tmp;
ll i;
ll m=sqrt(n*1.0);
if(m*10<=n) m=m*10;
ll s=0;
for(i=1;i<=m;i++){
s+=n%i;
tmp=i;
}
ans=ans+s;
ll k=n/(tmp+1),l,r,cnt1,cnt2;
for(l=tmp+1;k!=0;k--,l=r+1){
r=n/k;
cnt1=(n%l)/k;
cnt2=cnt1+1;
ans=ans+BigInt((n%r)*cnt2);
//printf("%I64d %I64d\n",n%r,cnt2);
if(cnt1&1) cnt2>>=1;
else cnt1>>=1;
ans=ans+BigInt(k*cnt1)*BigInt(cnt2);
}
printf("Case %d: ",cas++);
ans.output();
/*ll ans1=0;
for(ll i=1;i<=n;i++){
ans1+=n%i;
}
printf("Case %d: %I64d\n",cas++,ans1);*/
}
int main() {
#ifndef ONLINE_JUDGE
//freopen("in.txt","r",stdin);
#endif
scanf("%d",&t);
while(t--){
init();
work();
}
return 0;
}
XTU1205 Range
一开始觉得用线段树,写了一会发现太难写,就觉得还有其他做法
想了个用ST+二分的做法,结果超时了。。。
然后搜解题报告,说是用单调栈,据说单调栈在处理最大最小值时会很好用
结合我以前后缀数组时用过的一个单调栈来看,单调栈主要解决在连续多个数之间的大小比较
注释过了的是AC代码,没注释的是ST+二分的代码,虽然超时了,但觉得这应该也是一种思路
#include<stdio.h>
#include<string.h>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<math.h>
using namespace std;
#define out(x) cout<<#x<<": "<<x<<endl
const double eps(1e-8);
const int maxn=101000;
const long long inf=-1u>>1;
typedef long long ll;
int n,a[maxn],Max[maxn][20],Min[maxn][20];
void init_rmq(){
for(int i=1;i<=n;i++) Min[i][0]=Max[i][0]=a[i];
for(int j=1;(1<<j)<=n;j++){
for(int i=n;i>=1;i--){
if(i+(1<<(j-1))>n) {//上一层的一半长度都已经超过了,则这一层肯定也会超过,直接继承
Max[i][j]=Max[i][j-1];
Min[i][j]=Min[i][j-1];
}
else{
Max[i][j]=max(Max[i][j-1],Max[i+(1<<(j-1))][j-1]);
Min[i][j]=min(Min[i][j-1],Min[i+(1<<(j-1))][j-1]);
}
}
}
}
int max_ask_rmq(int l,int r){
int j=log(r-l+1.0)/log(2.0);
return max(Max[l][j],Max[r-(1<<j)+1][j]);
}
int min_ask_rmq(int l,int r){
int j=log(r-l+1.0)/log(2.0);
return min(Min[l][j],Min[r-(1<<j)+1][j]);
}
void init() {
scanf("%d",&n);
for(int i=1;i<=n;i++) {
scanf("%d",&a[i]);
}
init_rmq();
}
int find_greater_r(int l,int r,int i){
if(l>r) return l-1;
if(max_ask_rmq(l,r)<a[i]) return r;
int mid=(l+r)>>1;
while(l+1<r){
if(max_ask_rmq(l,mid)<a[i]) l=mid;
else r=mid;
mid=(l+r)>>1;
}
if(a[l]>=a[i]) return l-1;
else return r-1;
}
int find_greater_l(int l,int r,int i){
if(max_ask_rmq(l,r)<=a[i]) return l;
int mid=(l+r)>>1;
while(l+1<r){
if(max_ask_rmq(mid,r)<=a[i]) r=mid;
else l=mid;
mid=(l+r)>>1;
}
return r;
}
int find_less_r(int l,int r,int i){
if(l>r) return l-1;
if(min_ask_rmq(l,r)>a[i]) return r;
int mid=(l+r)>>1;
while(l+1<r){
if(min_ask_rmq(l,mid)>a[i]) l=mid;
else r=mid;
mid=(l+r)>>1;
}
if(a[l]<=a[i]) return l-1;
else return r-1;
}
int find_less_l(int l,int r,int i){
if(min_ask_rmq(l,r)>=a[i]) return l;
int mid=(l+r)>>1;
while(l+1<r){
if(min_ask_rmq(mid,r)>=a[i]) r=mid;
else l=mid;
mid=(l+r)>>1;
}
return r;
}
void work() {
ll ans=0;
for(int i=1;i<=n;i++){
int left,right;
left=find_greater_l(1,i,i);
right=find_greater_r(i+1,n,i);
ans+=(ll)(right-i+1)*(i-left+1)*a[i];//该数作为最大值被计算了times次
left=find_less_l(1,i,i);
right=find_less_r(i+1,n,i);
//printf("%d\n",i);
ans-=(ll)(right-i+1)*(i-left+1)*a[i];
//printf("%d\n",right);
}
ans+=n*(n+1)/2;
printf("%I64d\n",ans);
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
int t,cas=1;
scanf("%d",&t);
while(t--){
init();
printf("Case %d: ",cas++);
work();
}
return 0;
}
/*
#include<stdio.h>
#include<string.h>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<math.h>
using namespace std;
#define out(x) cout<<#x<<": "<<x<<endl
const double eps(1e-8);
const int maxn=101000;
const long long inf=-1u>>1;
typedef long long ll;
int n,a[maxn],sta1[maxn],sta2[maxn],suml1[maxn],sumr1[maxn],suml2[maxn],sumr2[maxn];
void init() {
<span style="white-space:pre"> </span>scanf("%d",&n);
<span style="white-space:pre"> </span>for(int i=1;i<=n;i++) {
<span style="white-space:pre"> </span>scanf("%d",&a[i]);
<span style="white-space:pre"> </span>}
}
void work() {
<span style="white-space:pre"> </span>ll ans=0;
<span style="white-space:pre"> </span>int top1=1,top2=1,l1,l2,r1,r2;
<span style="white-space:pre"> </span>sta1[0]=sta2[0]=0;
<span style="white-space:pre"> </span>for(int i=1;i<=n;i++){//与左边的相比作为最大值
<span style="white-space:pre"> </span>while(top1>1&&a[i]>=a[sta1[top1-1]]) top1--;
<span style="white-space:pre"> </span>l1=sta1[top1-1]+1;
<span style="white-space:pre"> </span>sta1[top1++]=i;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>while(top2>1&&a[i]<=a[sta2[top2-1]]) top2--;
<span style="white-space:pre"> </span>l2=sta2[top2-1]+1;
<span style="white-space:pre"> </span>sta2[top2++]=i;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>suml1[i]=i-l1+1;
<span style="white-space:pre"> </span>suml2[i]=i-l2+1;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>top1=top2=1;
<span style="white-space:pre"> </span>sta1[0]=sta2[0]=n+1;
<span style="white-space:pre"> </span>for(int i=n;i>=1;i--){
<span style="white-space:pre"> </span>while(top1>1&&a[i]>a[sta1[top1-1]]) top1--;
<span style="white-space:pre"> </span>r1=sta1[top1-1]-1;
<span style="white-space:pre"> </span>sta1[top1++]=i;
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>while(top2>1&&a[i]<a[sta2[top2-1]]) top2--;
<span style="white-space:pre"> </span>r2=sta2[top2-1]-1;
<span style="white-space:pre"> </span>sta2[top2++]=i;
<span style="white-space:pre"> </span>sumr2[i]=r2-i+1;
<span style="white-space:pre"> </span>sumr1[i]=r1-i+1;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>ans=0;
<span style="white-space:pre"> </span>for(int i=1;i<=n;i++) {
<span style="white-space:pre"> </span>ans+=(ll)suml1[i]*sumr1[i]*a[i];
<span style="white-space:pre"> </span>ans-=(ll)suml2[i]*sumr2[i]*a[i];
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>ans+=n*(n+1)/2;
<span style="white-space:pre"> </span>printf("%I64d\n",ans);
}
int main() {
<span style="white-space:pre"> </span>#ifndef ONLINE_JUDGE
<span style="white-space:pre"> </span>//freopen("in.txt","r",stdin);
<span style="white-space:pre"> </span>#endif
<span style="white-space:pre"> </span>int t,cas=1;
<span style="white-space:pre"> </span>scanf("%d",&t);
<span style="white-space:pre"> </span>while(t--){
<span style="white-space:pre"> </span>init();
<span style="white-space:pre"> </span>printf("Case %d: ",cas++);
<span style="white-space:pre"> </span>work();
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>return 0;
}
*/
XTU1205
Dormitory's Elevator
dp,这道题不同于以前的对某个点选或不选的地方在于,第i层可能由第i-2层,i-3层,i-4层的影响
画一下图发现受i-4层影响是不可能的,因为这样的话可以在i-2层停。。。
这样题目就变得简单了
dp[i]表示前i层,停在第i层时最小消耗的能量
还有很重要的一点,这道题有问题,A和B给出的时候应该是先B后A,害我无限WA
#include<stdio.h>
#include<string.h>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<math.h>
using namespace std;
#define out(x) cout<<#x<<": "<<x<<endl
const double eps(1e-8);
const int maxn=100100;
const long long inf=-1u>>1;
typedef long long ll;
int n,m,up,down;
int a[maxn],dp[maxn];
void init() {
int tmp;
memset(a,0,sizeof(a));
scanf("%d%d%d%d",&n,&m,&up,&down);
for(int i=0;i<=n;i++) dp[i]=inf;
for(int i=0;i<m;i++) {
scanf("%d",&tmp);
a[tmp]++;
}
}
//dp[i]:前i层,电梯停在第i层花费的最小能量
void work() {
int mini=min(up,down);
dp[0]=0;
dp[1]=0;
dp[2]=a[1]*down;
dp[3]=mini*a[2];
int ans=0;
for(int i=4;i<=n;i++){
dp[i]=min(dp[i-2]+a[i-1]*mini,dp[i-3]+min(up,down*2)*a[i-1]+min(down,up*2)*a[i-2]);
}
ans=min(dp[n],dp[n-1]+a[n]*up);
printf("%d\n",ans);
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
int t;
scanf("%d",&t);
for(int cas=1;cas<=t;cas++){
init();
printf("Case %d: ",cas);
work();
}
return 0;
}
XTU 1207 Welcome to XTCPC
纯粹就是打广告的题。。。-_-||
#include<stdio.h>
#include<string.h>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<math.h>
using namespace std;
#define out(x) cout<<#x<<": "<<x<<endl
const double eps(1e-8);
const int maxn=10100;
const long long inf=-1u>>1;
typedef long long ll;
char s[1000];
void init() {
scanf("%s",s);
}
void work() {
int len=strlen(s),cnt=0,ans=1;
for(int i=0;i<len;i++){
if(ans==1&&s[i]=='X') ans++;
else if(ans==2&&s[i]=='T') ans++;
else if(ans==3&&s[i]=='C') ans++;
else if(ans==4&&s[i]=='P') ans++;
else if (ans==5&&s[i]=='C') ans++;
if(ans==6) break;
}
if(ans==6) printf("Yes\n");
else printf("No\n");
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
int t,cas=1;
scanf("%d",&t);
while(t--){
init();
printf("Case %d: ",cas++);
work();
}
return 0;
}
XTU1209 Alice and Bob
横的能减的次数+竖的能减的次数,对2取模
#include<stdio.h>
#include<string.h>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<math.h>
using namespace std;
#define out(x) cout<<#x<<": "<<x<<endl
const double eps(1e-8);
const int maxn=10100;
const long long inf=-1u>>1;
typedef long long ll;
int w,h;
void init() {
scanf("%d%d",&w,&h);
}
void work() {
int cnt1=0,cnt2=0;
while(w){
if((w&(1<<cnt1))==0) cnt1++;
else break;
}
while(h){
if((h&(1<<cnt2))==0) cnt2++;
else break;
}
int cnt=cnt1+cnt2;
//printf("%d\n",cnt);
if(cnt&1) printf("Alice\n");
else printf("Bob\n");
}
int main() {
#ifndef ONLINE_JUDGE
//freopen("in.txt","r",stdin);
#endif
int t,n,cas=1;
scanf("%d",&t);
while(t--){
init();
printf("Case %d: ",cas++);
work();
}
return 0;
}
XTU1210 还是因为n只有10e6,直接递推就好了
#include<stdio.h>
#include<string.h>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<math.h>
using namespace std;
#define out(x) cout<<#x<<": "<<x<<endl
const double eps(1e-8);
const int maxn=10100;
const long long inf=-1u>>1;
typedef long long ll;
int n;
int a[1000005],b[10];
void init() {
scanf("%d",&n);
}
int judge(int m) {
int len=0,cnt=0;
while(m){
b[++len]=m%10;
if(b[len]==7) cnt++;
m/=10;
}
if(cnt==len||cnt==len-1) return 1;
else return 0;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
for(int i=1;i<=1000000;i++) {
if(judge(i)) a[i]=a[i-1]+1;
else a[i]=a[i-1];
}
int t,cas=1;
scanf("%d",&t);
while(t--){
init();
printf("Case %d: ",cas++);
printf("%d\n",a[n]);
}
return 0;
}