1.热身赛B题:
一开始,就用map存了下每个数字出现的次数,然后扫一遍,碰见1就输出(WA的不知所措)中午,跟西电大佬吃饭的时候,发现他也是用的map,然后iterator扫一遍过了,用队列的我表示从来没这么玩过(大佬下午就全场第三orz);然后SNNU大佬告诉我标程。。xor的逆运算是xor,输入的时候和0异或就好,最后剩下的就是答案,我竟然忘了(ys我对不起你),但是依然不知道,第一发为什么错。。有个学长说他用map也没过,换set就好了。。。(ys告诉我这水题,尽量别用stl。。。然后下午A题崩了用了一堆stl无限WA)
2.正式赛(引用大佬的)
A:开个数组score[i]保存A-Z的分数,最后输出最高的,注意分数相同字典序,(如此水题我竟然1个半小时卡了。。全场过的人辣么多,死在热身赛的stl上了,水题水做)
C:三进制计算器:3进制阶乘统计末尾0,现场·我是打表3^k,然后可以整除就加对应的k也算是过了,不过标程很强
证明:一个数N!=M*3^k,k就是0的个数,易知,当K最大时M与3互质,所以我们只要分离出N!中所有的3即可。也就是说其实计算N! = m*3^k中K的最大值,只要不断将n/3的结果加到K中去就好,每次执行一次操作n=n/3.显示意义就是计算连续的N个数中3的倍数,9的倍数,27的倍数......所有之和,同时在每次计算时3的i次方被恰好会被计算i次,从而保证程序的正确性。
#include <iostream>
#include <ctime>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <vector>
#include <cstdlib>
using namespace std;
int main()
{
int t;
scanf("%d",&t);
long long n;
while(t--)
{
long long sum=0;
scanf("%lld",&n);
while(n!=0)
{
sum+=n/3;
n=n/3;
}
printf("%lld\n",sum);
}
return 0;
}
D:题目要求N个点中距离距离最近的两个点的距离,看似是一道平面上N个点求最短距离的KD树题目(我就是这么想的,一开始果断放),但是仔细观察题目中所给的距离D的定义D = |(X2-X1)+(Y2-Y1)| 可做如下变形:D = |(x2+y2)-(x1+y1)|;(最后,好像10几分钟的时候,瞟了两眼,想死啊,幸好发现了)
E:这题弱连输入都不会,感觉gets()有问题,下来学习了一下,学到了新函数,我这string类和输入输出看样子得大补;
解法:每次如果行末有";"就增加缩进,有空行就减少缩进;比赛的时候,好像因为生成数据的系统和评测机的不一样,要在行末多加个空行。
解法:每次如果行末有";"就增加缩进,有空行就减少缩进;比赛的时候,好像因为生成数据的系统和评测机的不一样,要在行末多加个空行。
#include <iostream>
#include <string>
#include <cstdio>
using namespace std;
string s;
int tab;
int main()
{
//freopen("input.txt","r",stdin);
//freopen("output.txt","w",stdout);
tab=0;
bool flag=0;
while(getline(cin,s))//getline
{
if(s.empty())
{
for(int i=0;i<tab;i++)
cout<<" ";
cout<<endl;
tab-=4;
continue;
}
if(s[s.length()-1]==':')
flag=1;
for(int i=0;i<s.length();i++)
{
if(s[i]==',')
{
s.insert(i+1," ");
i++;
}
}
for(int i=0;i<tab;i++)
cout<<" ";
cout<<s<<endl;
if(flag)
{
tab+=4;
flag=0;
}
}
return 0;
}
F:这类状态压缩问题之前一直没做过,一开始的思路是:dp[i][3][3][3][3][3][3][3][3][3][3][m]表示状态i指的是前i件物品,后面的10维0表示偶数,1表示奇数,2表示这一维未被使用,m表示魅力值,显然魅力m<=100000,加上前面的维,数组开不了。然后,又想可以常规降维
dp[i][3][3][3][3][3][3][3][3][3][3]=m;这显然也挺麻烦的,最后看了标程,dp[i][W]=m,W是用2进制的形式存下当前状态,解决了维度不确定的问题,还有数组开不下的问题,最强的是又利用了一次xor的性质,
W=W^X,每次xor表示这一位出现次数的奇偶,相当于将01背包中的体积转化为奇偶状态,dp[0][0]=0;其余为-1,表示不能直接到达
#include<bits/stdc++.h>
using namespace std;
int bag[1003][1111];
int main()
{
//freopen("test.in","r",stdin);
//freopen("test.out","w",stdout);
int T;
cin>>T;
while(T--)
{
int n,m;
cin>>n>>m;
int goal=1<<m;
memset(bag,-1,sizeof(bag));
bag[0][0]=0;
for(int i=1 ; i<=n ; i++)
{
int q,s;
cin>>q>>s;
int w=0;
for(int j=0; j<s; j++)
{
int c;
cin>>c;
w=w|(1<<(c-1));//压缩成二进制***
}
for(int j=0; j<goal; j++)
{
if(bag[i-1][j]==-1)
continue;
bag[i][j^w]=max(bag[i][j^w],bag[i-1][j]+q);
bag[i][j]=max(bag[i][j],bag[i-1][j]);
}
}
cout<<bag[n][goal-1]<<endl;
}
return 0;
}
2)卡特兰数法:dp[n]=h[n-1];h[n]=C(2n,n)/(n+1)=C(2n,n)-2C(2n,n-1)(n=0,1,2,...)
I:2进制大数加法,乘法,记下模板:
#include<bits/stdc++.h>
using namespace std;
char a[2003];
char b[2003];
char c[2003];
void toadd(char sa[],char sb[],int len)
{
for(int i=0; i<len; i++)
{
if((sa[i]&sb[i])=='1')
{
for(int j=i; j<=len; j++)
{
if(sa[j]=='1')
{
sa[j]='0';
}
else
{
sa[j]='1';
break;
}
}
}
else
{
sa[i]=max(sa[i],sb[i]);
}
}
}
int main()
{
int T;
cin>>T;
getchar();
while(T--)
{
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
int la=0;
int lb=0;
char ch;
int opr;
while(1)
{
ch=getchar();
if(ch=='*')
{
opr=1;
break;
}
else if(ch=='+')
{
opr=0;
break;
}
a[la++]=ch;
}
while(1)
{
ch=getchar();
if(ch=='\n')
break;
b[lb++]=ch;
}
for(int i=0 ; i<la/2 ; i++)
{
int t=a[i];
a[i]=a[la-i-1];
a[la-i-1]=t;
}
for(int i=0 ; i<lb/2 ; i++)
{
int t=b[i];
b[i]=b[lb-i-1];
b[lb-i-1]=t;
}
if(opr==0)
{
toadd(a,b,max(la,lb));
}
else
{
for(int i=0 ; i<2002 ; i++)
c[i]='0';
for(int i=0,j=lb-1; i<lb; i++,j--)
{
if(b[i]=='1')
{
toadd(c+i,a,la+i);
}
}
strcpy(a,c);
}
la=0;
for(int i=2002 ; i>0 ; i--)
{
if(a[i]>'0')
{
la=i;
break;
}
}
for(int i=la; i>=0; i--)
{
cout<<a[i];
}
cout<<endl;
}
return 0;
}
(难题看懂以后补上)
orz