杭电多校第三场
题目链接
1004 Game on Plane
思路
这道题也是在看题解之后才写出来的,当时想到斜率这一方面了,但是还是没有理解清题意,所以没有明确的思路。Alice 为了让 Bob 与尽量多的直线相交,最优策略就是最小化斜率出现次数的最大值,所以不断从每种斜率的直线中各选一种即可。
附上代码
#include <bits/stdc++.h>
#include <iostream>
#define inf 0x3f3f3f3f
#define mod 1000000007
#define lmax 200005
#define pi 3.141592653589793238462643383279
#define eps 1e-7
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double type;
typedef pair<int,int>P;
const int N=100005;
int t,n,i,j,k,f[N];
P a[N];
int gcd(int a,int b)//求最大公因数
{
return b?gcd(b,a%b):a;
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(i=1; i<=n; i++)
{
int x1,y1,x2,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
int dx=x2-x1,dy=y2-y1;
if(dx==0)dy=1;
else if(dy==0)dx=1;
else
{
if(dx<0)dx=-dx,dy=-dy;
int d=gcd(abs(dx),abs(dy));
dx/=d,dy/=d;
}
a[i]=P(dx,dy);//将直线的斜率传到a数组中
}
sort(a+1,a+n+1);//进行排序
for(i=1; i<=n; i++)
f[i]=0;
for(i=1; i<=n; i=j)
{
for(j=i; j<=n&&a[i]==a[j]; j++);//相当于计算从i开始有几条斜率相同的直线
for(k=1; k<=j-i; k++)f[k]++;//将结果保存至f数组中
}
for(i=j=1; i<=n; i++)
{
while(!f[j])j++;
f[j]--;
printf("%d\n",i-j);//根据f数组得出结果
}
}
return 0;
}
1007 Photoshop Layers
思路
这道题仔细分析可以发现就是一道求和的题目,给定n个图层,每个图层分为两种模式,模式1的话就是用当前的图层直接覆盖之前的图层,而模式2的话就是在原来的图层基础上加上当前的图层。
直接暴力解决一定会超时,所以要分析其中的规律,可以看出,只要所查询的区间中出现了1模式的图层,那么该区间就可以转换为这一点和右端点之间的查询,最后就可以转换成某一段由1个“1”模式和n个“2”模式相加的情况。
我们在构造初始数组的时候直接也就按照这个规律来构造即可。
附上代码
#include <bits/stdc++.h>
#include <iostream>
#define inf 0x3f3f3f3f
#define mod 1000000007
#define lmax 200005
#define pi 3.141592653589793238462643383279
#define eps 1e-7
using namespace std;
typedef long long ll;
typedef double type;
int biao[lmax];//标记模式
int color1[lmax];//颜色的三个部分即R,G,B
int color2[lmax];
int color3[lmax];
int jilu[lmax];//记录模式为“1”的位置
int main()
{
int t,n,q,l,r;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&q);
int xi=0;
for(int i=1; i<=n; i++)
{
scanf("%d %x",&biao[i],&color1[i]);
color3[i]=color1[i]%256;//直接将每一部分的值赋给这一部分的数组
color1[i]=color1[i]/256;
color2[i]=color1[i]%256;
color1[i]=color1[i]/256;
if(biao[i]==1)
{
jilu[xi]=i;
xi++;
}
else
{
color1[i]+=color1[i-1];//记录由“1”模式开始的这一段的前缀和
color2[i]+=color2[i-1];
color3[i]+=color3[i-1];
}
}
for(int k=1; k<=q; k++)
{
scanf("%d%d",&l,&r);
int i=l;//用i表示左端点,r还表示右端点
int bb=upper_bound(jilu,jilu+xi,r)-jilu;//找到左端点的位置
if(biao[r]==1)
{
i=r;
}
else
{
if(jilu[bb-1]>=l)
i=jilu[bb-2];
else
i=l;
}
if(biao[i]==1)
printf("%02X%02X%02X\n",min(color1[r],255),min(color2[r],255),min(color3[r],255));
else
printf("%02X%02X%02X\n",min(color1[r]-color1[i-1],255),min(color2[r]-color2[i-1],255),min(color3[r]-color3[i-1],255));
}
}
return 0;
}
/*
3 2
3 1 2
4 2
4 1 3 2
*/
1009 Rise in Price
待补
1011 Segment Tree with Pruning
思路
这道题是队友写的,我听了一下思路,基本就是围绕奇偶性来寻找规律,然后将得到的答案输出。
附上代码
#include <bits/stdc++.h>
#include <iostream>
#define inf 0x3f3f3f3f
#define mod 1000000007
#define lmax 200005
#define pi 3.141592653589793238462643383279
#define eps 1e-7
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double type;
ull qpow(long long a, int n)
{
ull ans = 1;
while(n)
{
if(n&1)
{
ans *= a;
}
a *= a;
n >>= 1;
}
return ans;
}
int main()
{
cin.sync_with_stdio(0);
cin.tie(0);
int t;
cin >> t;
ull res;
while(t--)
{
res = 0;
ull k, n;
cin >> k >> n;
if(n == 1)
{
cout << 2 * k - 1 << endl;
continue;
}
ull c;
c = k / n;
int lay = log2(c);
res += (qpow(2,lay + 1)-1);
if((c = k / qpow(2, lay)) > n)
{
res += qpow(2, lay) * 2;
}
else if((c = k / qpow(2, lay)) == n)
{
res += 2 * (k % qpow(2, lay));
}
cout << res << endl;
}
return 0;
}