Problem A:NEFU2122 熊熊对对碰
//#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
map<pair<int, int>, int> a;
pair<int, int> p;
int main()
{
int n;
//ios::sync_with_stdio(false);
scanf("%d", &n);
while(n--)
{
int x, y;
scanf("%d%d", &x, &y);
if(a.count({-1*x, -1*y})) a[{-1*x, -1*y}]++;
else a[{x, y}]++;
}
int cnt=0;
for(map<pair<int, int>, int>::iterator it=a.begin(); it!=a.end(); it++)
{
if(!(it->second%2))
cnt += it->second;
}
printf("%d\n", cnt);
return 0;
}
Problem B:NEFU2120 秘籍
这题一看就是前缀和嘛,正好前一天写了一篇博客。 然后打了暴力,吸氧水过去了。代码就不贴了。
贴一下尺取法的代码:
//#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
int n, k, a[300010];
int l, r;
bool check()
{
int tmp = 0;
l = 1;
for(r=1; r<=n; r++)
{
tmp += a[r];
while(tmp>k && l<r)
{
tmp -= a[l];
l++;
}
if(tmp==k) return 1;
}
return 0;
}
int main()
{
ios::sync_with_stdio(false);
cin>>n>>k;
for(int i=1; i<=n; i++)
cin>>a[i];
if(check()) cout<<l<<" "<<r<<endl;
else cout<<"tiangeniupi"<<endl;
return 0;
}
Problem C:NEFU2103 jwGG的签到题
打表找规律题,这真不是签到题。(我的签退题)
先暴力打表到1e4或1e5
int line(int x, int y)
{
int tmp=y;
while(tmp)
{
tmp /= 10;
x *= 10;
}
return x+y;
}
int main()
{
for(int a=1; a<=1000; a++)
for(int b=1; b<=10000; b++)
if(a*b == line(a, b)-a-b)
printf("%d %d\n", a, b);
return 0;
}
找出规律:只与y有关且y只能为9,99,999……
然后即可根据表写出代码
typedef long long ll;
int t;
ll num[18] = {9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999, 9999999999, 99999999999, 999999999999, 9999999999999, 99999999999999, 999999999999999, 9999999999999999, 99999999999999999, 999999999999999999};
int main()
{
scanf("%d", &t);
for(int mcv=1; mcv<=t; mcv++)
{
unsigned long long a, b, cnt=0;
scanf("%llu%llu", &a, &b);
//int i;
for(int i=0; i<18; i++)
{
if(num[i]<=b)
cnt++;
else
{
//printf("%llu\n", cnt*a);
break;
}
}
cnt *= a;
printf("%llu\n", cnt);
}
return 0;
}
Problem D:NEFU2133 jwMM的疯狂A-B
这才是签到题,纯set做就可以了。
//#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
int n, m;
int x;
set<int> a, b;
int main()
{
ios::sync_with_stdio(false);
scanf("%d%d", &n, &m);
for(int i=1; i<=n; i++)
{
scanf("%d", &x);
a.insert(x);
}
for(int i=1; i<=m; i++)
{
scanf("%d", &x);
b.insert(x);
}
int cnt=0;
for(set<int>::iterator it=a.begin(); it!=a.end(); it++)
{
if(!b.count(*it))
{
printf("%d\n", *it);
cnt++;
}
}
if(!cnt) printf("So crazy!!!\n");
return 0;
}
Problem E:NEFU2126 煊哥的难题
好难啊。
Li与Lj至少有一个公共点:相交或重合
i 从 1 到 n 遍历所有直线,每次 ans 都加上 i - 1 - 平行Li的个数。
需要特判直线垂直于x轴的情况
//#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
map<double, int> kis; // 斜率相等
map<double, map<double, int> > kbis; // 重合
map<double, int> vertx; // 垂直于x轴
int main()
{
ios::sync_with_stdio(false);
int n, x1, y1, x2, y2, x0=0;
long long ans = 0;
cin>>n;
for(int i=1; i<=n; i++)
{
cin>>x1>>y1>>x2>>y2;
if(x1==x2) // 垂直于x轴
{
int num = x0-vertx[x1*1.0]; // 平行
ans += i-1-num;
x0++; // 平行或重合
vertx[x1*1.0]++; // 重合
}
else
{
int x=x1-x2, y=y1-y2;
double k = y*1.0/x;
double b = y1*1.0-k*x1;
int num = kis[k]-kbis[k][b]; // 平行
ans += i-1-num;
kis[k]++; // 平行或重合
kbis[k][b]++; // 重合
}
}
cout<<ans<<endl;
return 0;
}
Problem F:NEFU2106 jwGG与yzMM的字符串
直到听了题解才知道怎么能在有取模操作的情况下解密。
//#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
struct node{
int x, y;
}pass[100010];
char a[52], str[1010][1010], ans[130][130];
void init()
{
for(int i=0; i<52; i++)
{
if(i<26) a[i] = i+'A';
else a[i] = i+'a'-26;
//cout<<a[i]<<" ";
}
for(int i=0; i<52; i++)
for(int j=0; j<52; j++)
{
int z = (i+j)%52;
ans[a[j]][a[z]] = a[i];
}
}
int main()
{
ios::sync_with_stdio(false);
int n, m, xi, yi;
cin>>n>>m;
init();
for(int i=1; i<=m; i++)
cin>>pass[i].x>>pass[i].y;
for(int i=1; i<=n; i++)
cin>>str[i];
for(int i=m; i>=1; i--) // 解密-倒序
{
int xi=pass[i].x, yi=pass[i].y;
int l1=strlen(str[xi]), l2=strlen(str[yi]);
for(int j=0; j<l2; j++)
str[yi][j] = ans[str[xi][j%l1]][str[yi][j]];
}
for(int i=1; i<=n; i++)
cout<<str[i]<<endl;
return 0;
}
Problem G:NEFU2107 jwGG与bwMM的字符串
对于字符串前缀的介绍可以参考此博客kmp部分。当然此题要求空串也算前缀。
//#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
string str;
int t;
int check[100010];
int main()
{
ios::sync_with_stdio(false);
cin>>t;
while(t--)
{
int n, x;
cin>>n>>x;
cin>>str;
int cnt0=0, cnt1=0, ans=0;
if(!x) ans++; // 空串也是前缀
bool flag = false;
for(int i=0; i<n; i++) //得到0和1的个数
{
if(str[i]-'0') cnt1++;
else cnt0++;
check[i] = x+cnt1-cnt0; // 预处理x与num(pre,0)-num(pre,1)的关系
}
if(cnt0==cnt1) // 只有0和1的数目相等时才会出现无数个等于x的平衡系数
for(int i=0; i<n; i++)
{
if(!check[i])
{
flag = true;
break;
}
else continue;
}
else
for(int i=0; i<n; i++)
if(check[i]%(cnt0-cnt1)==0 && check[i]/(cnt0-cnt1)>=0)
ans++;
if(flag) cout<<-1<<endl;
else cout<<ans<<endl;
}
return 0;
}
Problem H:NEFU2123 库特放书
出题人gls解释了为什么直接暴力不会超时:
H题再解释一下为什么直接暴力不用二分在时间上是可行的吧,因为我看所有通过代码都写的枚举容量的上界是sum,但是如果上界真的是sum的话在时间上理论上是不可行的,这一点上并不是我数据出水了,是它的下界可以视为max(ceil(sum / k),maxV),上界为ceil(sum / k)+MAXV
所以枚举次数为二者之差远达不到sum次,最多也不会超过1000次所以从下界while(1)向上寻找在时间上是可行的
//#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
int t, n, m;
int v[1005];
bool box[1005];
bool put(int vol)
{
fill(box, box+1005, 0);
for(int i=1; i<=m; i++)
{
int tmp=0;
for(int j=1; j<=n; j++)
if(tmp+v[j]<=vol && !box[j])
{
box[j] = 1;
tmp += v[j];
}
}
for(int i=1; i<=n; i++)
if(!box[i]) return 0;
return 1;
}
int main()
{
ios::sync_with_stdio(false);
scanf("%d", &t);
for(int mcv=1; mcv<=t; mcv++)
{
int sum=0, tmp;
scanf("%d%d", &n, &m);
for(int i=1; i<=n; i++)
{
scanf("%d", &v[i]);
sum += v[i];
}
sort(v+1, v+n+1);
reverse(v+1, v+n+1);
for(int i=sum/m; i<=sum; i++)
if(put(i))
{
tmp = i;
break;
}
printf("Case #%d: %d\n", mcv, tmp);
}
return 0;
}