不知不觉到了第二届新生赛,此时的我已经是退休老油条了,看着xdu-icpc队伍逐渐壮大,甚是欣慰。预祝即将到来的第三届新生赛顺利。
Problem A Easy Problem
思路:正奇数数列最大长度,打标找规律即可发现,答案即为输入的开方数
#include <bits/stdc++.h>
using namespace std;
const double eps = 1e-5;
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
printf("%d\n",(int)sqrt(double(n)+eps));
}
return 0;
}
Problem B 希希的多项式
思路:多项式找规律
* ** n0=1
1 00 n1=x
1 -1 n2=x^2-1
1 -3 n3=x^3-3x
1 -6 n4=x^4-6x^2+3
1 -10 n5=x^5-10x^3+15x
1 -15 n6=x^6-15x^4+45x^2-15
总结不难发现,第一项必为1,第二项为前n项和
#include <bits/stdc++.h>
using namespace std;
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
long long re = (-1LL) * (long long)(n) * (long long)(n-1) / 2LL;
printf("%d %lld\n",1,re);
}
return 0;
}
Problem C 编辑器的选择
思路:16进制乘法,进制转换,说白了其实这题最大的难度在数据读入上,含空格的整行读取,当然是while(getline(cin,in))。
最后注意一下string的初始化
#include <bits/stdc++.h>
using namespace std;
map<string,int> dic;
int main()
{
dic["zero"]=0;
dic["one"]=1;
dic["two"]=2;
dic["three"]=3;
dic["four"]=4;
dic["five"]=5;
dic["six"]=6;
dic["seven"]=7;
dic["eight"]=8;
dic["nine"]=9;
dic["ten"]=10;
dic["eleven"]=11;
dic["twelve"]=12;
dic["thirteen"]=13;
dic["fourteen"]=14;
dic["fifteen"]=15;
string in;
while(getline(cin,in))
{
int a=0,b=0;
string temp = "";
int len = in.size();
for(int i=0;i<len;i++)
{
if(in[i]==' ')
{
//cout << temp << endl;
a = a*16 + dic[temp];
temp.clear();
//cout << a << endl;
}
else
temp += in[i];
}
a = a*16 + dic[temp];
getline(cin,in);
len = in.size();
temp.clear();
for(int i=0;i<len;i++)
{
if(in[i]==' ')
{
b = b*16 + dic[temp];
temp.clear();
}
else
temp += in[i];
}
b = b*16 + dic[temp];
//cout << a << " " << b << endl;
cout << a*b << "\n";
}
return 0;
}
Problem D Love Live! 南琴梨篇
思路:寻找树上两点的公共子序列(LCA)。看似是到很复杂的lca题,但由于树的特殊性,相同前缀的数必定在相同分叉上,于是这题就转换为了求两串的最长公共前缀
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e4+5;
char a[maxn],b[maxn],re[maxn];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int k;
scanf("%d%s%s",&k,a,b);
int alen = strlen(a), blen = strlen(b);
int pos = 0;
while(pos<alen&&pos<blen&&a[pos]==b[pos])
{
re[pos]=a[pos];
pos++;
}
if(pos==0)
printf("I'm sorry, KOTORI!");
else
for(int i=0;i<pos;i++)
printf("%c",re[i]);
printf("\n");
}
return 0;
}
Problem E or2?Scum!
思路:判断某个数是否为2,3,5,7的公约数,且为第几大公约数,貌似和素数很像,瞬间又成为一个十分困难的数学问题。实则不然,判断第几大公约数,即为求比该数小的公约数有多少个,那么完全可以分别求比该数小的2,3,5,7个字的约数,之后根据容斥定理即可得出
#include <bits/stdc++.h>
using namespace std;
const double eps = 1e-5;
int main()
{
long long n;
while(scanf("%lld",&n)!=EOF)
{
if(n%2==0||n%3==0||n%5==0||n%7==0)
{
/*long long sum = (long long)(((double)n-eps)/2.0) + (long long)(((double)n-eps)/3.0) + (long long)(((double)n-eps)/5.0) + (long long)(((double)n-eps)/7.0);
sum = sum - (long long)(((double)n-eps)/6.0) - (long long)(((double)n-eps)/10.0) - (long long)(((double)n-eps)/14.0) - (long long)(((double)n-eps)/15.0) - (long long)(((double)n-eps)/21.0) - (long long)(((double)n-eps)/35.0);
sum = sum + (long long)(((double)n-eps)/30.0) + (long long)(((double)n-eps)/42.0) + (long long)(((double)n-eps)/70.0) + (long long)(((double)n-eps)/105.0);
sum -= (long long)(((double)n-eps)/210.0);*/
long long sum = n/2LL +n/3LL + n/5LL + n/7LL;
sum = sum - n/6LL - n/10LL - n/14LL - n/15LL - n/21LL - n/35LL;
sum = sum + n/30LL + n/42LL + n/70LL + n/105LL;
sum -= n/210LL;
printf("or2 %lld\n",sum);
}
else
printf("Scum\n");
}
return 0;
}
Problem F zxy的长跑
思路:寻找最小欧拉回路,看似简单的题意,实则坑点十足
首先,可能含有多重变,其次,可能含有孤立点,处理不好的话这两个坑点足以让人崩溃,最后dfs记得回溯即可
#include <bits/stdc++.h>
using namespace std;
const int maxn = 510;
int ma[maxn][maxn];
//vector<int> ne[maxn];
//bool point[maxn];
//vector<int> re;
int re[maxn];
int ne[maxn];
int dfs(int p,int m,int n,int repos)
{
for(int i=1;i<=n;i++)
{
//if(st==i)
//continue;
if(repos<m&&ne[i]==1)
continue;
if(ma[p][i]>0)
{
ne[i]--;
ne[p]--;
ma[p][i]--;
ma[i][p]--;
//re.push_back(i);
re[repos++] = i;
//cout << i << "*" << repos << endl;
repos = dfs(i,m,n,repos);
if(repos<m+1)
{
ne[i]++;
ne[p]++;
ma[p][i]++;
ma[i][p]++;
repos--;
}
else
break;
//cout << pos << "*" << st << endl;
//st = i;
//break;
}
}
return repos;
}
int main()
{
memset(ma,0,sizeof ma);
//memset(point,false,sizeof point);
memset(ne,0,sizeof ne);
//re.clear();
int repos = 0;
int n,m;
scanf("%d%d",&n,&m);
/*for(int i=1;i<=n;i++)
{
ne[i].clear();
point[i].false;
}*/
for(int i=0;i<m;i++)
{
int a,b;
scanf("%d%d",&a,&b);
//ne[a].push_back(b);
//ne[b].push_back(a);
ma[a][b]++;
ma[b][a]++;
ne[a]++;
ne[b]++;
}
int collect = 0;
for(int i=1;i<=n;i++)
{
/*if(ne[i].size()%2==1)
{
point[i] = true;
collect++;
}*/
if(ne[i]%2==1)
{
//point[i] = true;
collect++;
}
}
//cout << collect << endl;
if(collect>2)
printf("-1\n");
else
{
int st = 1;
while(ne[st]==0)
st++;
//cout << st << endl;
if(collect==2)
{
for(int i=st;i<=n;i++)
{
if(ne[i]%2==1)
{
st=i;
break;
}
}
}
//re.push_back(st);
re[repos++] = st;
repos = dfs(st,m,n,repos);
/*int pos;
for(pos=0;pos<m;pos++)
{
int i;
for(i=1;i<=n;i++)
{
//if(st==i)
//continue;
if(pos<(m-1)&&ne[i]==1)
continue;
if(ma[st][i]>0)
{
ne[i]--;
ne[st]--;
ma[st][i]--;
ma[i][st]--;
re.push_back(i);
//cout << pos << "*" << st << endl;
st = i;
break;
}
}
if(i==n+1)
break;
}
//cout << pos << endl;
if(pos<m)*/
if(repos<m+1)
printf("-1\n");
else
{
//cout << re.size() << "*" << re[0] << " " << re[1] << "*" << m << endl;
for(int i=0;i<m;i++)
printf("%d ",re[i]);
printf("%d\n",re[m]);
}
}
return 0;
}
Problem G Twilight7和偶像
思路:和去年的那题类似,区间扫描点排序,不多说了
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
/*typedef struct POINT
{
int pos;
int mak;
}Point;
bool cmp(Point a,Point b)
{
if(a.mak>b.mak)
return true;
else if(a.mak==b.mak)
{
if(a.pos>b.pos)
return true;
else
return false;
}
else
return false;
}
Point num[maxn];*/
int tmp[maxn];
int num[maxn];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
memset(num,0,sizeof num);
memset(tmp,0,sizeof tmp);
int n,m;
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++)
{
int p,q;
scanf("%d%d",&p,&q);
tmp[p]++;
tmp[q+1]--;
}
int now = 0;
for(int i=1;i<=n;i++)
{
now += tmp[i];
//num[i-1].pos = i;
//num[i-1].mak = now;
num[i-1]=now;
}
//sort(num,num+n,cmp);
sort(num,num+n,greater<int>());
long long re = 0LL;
for(int i=0;i<n;i++)
re += (long long)(i+1) * (long long)(num[i]);
printf("%lld\n",re);
}
return 0;
}