补了差不多5个题,先把4个题的题解先写了。。。我感觉再不写,过几天更不会写了。。。
男神的演唱会 XDOJ 1060
题目链接
http://acm.xidian.edu.cn/problem.php?id=1160
题解
每个人每个时间段都有一个可能的不同状态,可能在也可能不在,对于每个询问,我们维护当前在听演唱会的这么一个人的集合,在线查询的,按照时间,依次往后推移。
代码
#include<iostream>
#include<queue>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<string>
#include<cctype>
#include<algorithm>
#include<vector>
#include<set>
using namespace std;
typedef struct qz
{
int flag;
int num,time;
};
bool cmp(const qz &a,const qz &b)
{
return a.time<b.time;
}
qz s[1000005];
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
for(int i=0;i<n;i++)
{
scanf("%d%d%d",&s[i].flag,&s[i].time,&s[i].num);
}
sort(s,s+n,cmp);
set<int>ss;
int j=0;
for(int i=0;i<m;i++)
{
int z,zz;
scanf("%d%d",&z,&zz);
while(s[j].time<z&&j<n)
{
if(s[j].flag==1){ss.insert(s[j].num);}
else ss.erase(s[j].num);
j++;
}
if(ss.count(zz)==1)printf("YES\n");
else printf("NO\n");
}
}
return 0;
}
修理电线 XDOJ 1185
题目链接
http://acm.xidian.edu.cn/problem.php?id=1185
题解
用二分的方法,对于每一个可行的解进行尝试,找出最佳的解的答案。
代码
#include<iostream>
#include<queue>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<string>
#include<cctype>
#include<algorithm>
#include<vector>
const int INF=1e9+5;
using namespace std;
int a[100005];
int m,k;
bool judge(int x)
{ int num=0;
int sum=0;
for(int i=0;i<m;i++)
{
if(sum+a[i]<x)
{
sum+=a[i];
}
else if(sum+a[i]==x)
{
sum=0;
num++;
}
else //(sum+a[i]==x)
{
sum=a[i];
num++;
}
// else
// {
// sum=a[i];
// num++;
// }
}
if(sum!=0)num++;
if(num>k)return true;
else return false;
}
int main()
{
while(scanf("%d%d",&m,&k)!=EOF)
{ memset(a,0,sizeof(a));
// int maxx=0;
for(int i=0;i<m;i++)
{
scanf("%d",&a[i]);
//maxx=max(maxx,a[i]);
}
// a[m]=0;
int le=0,ri=INF;
int mi;
for(int i=0;i<70;i++)
{
mi=(le+ri)/2;
// mi=3;
if(judge(mi))le=mi;
else ri=mi;
}
printf("%d\n",ri);
}
return 0;
}
Orz Huang God XDOJ1170
题目链接
http://acm.xidian.edu.cn/problem.php?id=1170
题解
题目数据有问题!!n=0&&m==0才退出,题目数据里面会有n=0&&m!=0的情况,会导致gcd==0出现RE的情况。。我RE了十来发。。不知道现在数据改了没。。。总的思路就是在B中找出满足是A倍数的值,那么就可以得到A*A的分数。。暴力果断T掉,需要找点技巧点的方法。例如n=16时:
除数:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
商 : 16 8 5 4 3 2 2 2 1 1 1 1 1 1 1 1
此时我们就可以发现一下奇特的规律,我们可以发现从16到9我们并没有必要用暴力的方法从16一直找到9,当我们找到除以9的商是1以后,n/9=1,n/1=16,这样就可以找到1的尾巴在16.。。。同理找2的区间。。找到16/6=2以后16/2=8 这样可以找到2的区间尾巴。。然后我们从小开始往大的找,知道找到A的最大值为止。。其中等差平方求和公式 x*(x+1) *(x *2+1)/6。。
代码
#include<iostream>
#include<queue>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<string>
#include<cctype>
#include<algorithm>
#include<vector>
#include<set>
typedef long long ll;
using namespace std;
//
//ll gcd(ll a,ll b)
//{
// if(a==0)return b;
// else return gcd(b%a,a);
//}
ll gcd(ll a,ll b)
{
while ( b>0)
{
ll c=a%b;
a=b;
b=c;
}
return a;
}
ll he(ll x)
{
return (x*(x+1)*(2*x+1))/6;
}
ll cal(ll l,ll r)
{
return he(r)-he(l-1);
}
int main()
{
ll n,m;
while(scanf("%lld%lld",&n,&m)!=EOF)
{ ll sum1=0,sum2=0;
ll t,en;
if(n==0||m==0)break;//这是可以AC的代码,其实题意上面有问题,不知道现在改了没。
for(ll i=1;i<=n;)
{
t=n/i;
en=n/t;
en=min(en,m);
sum1+=(t)*cal(i,en);
if(en==m)break;
i=en+1;
}
sum2=n*m;
ll jk=gcd(sum1,sum2);
printf("%lld/%lld\n",sum1/jk,sum2/jk);
}
return 0;
}
Orz Problem B XDOJ 1161
题目链接
http://acm.xidian.edu.cn/problem.php?id=1161
题解
这题并不是以网络流的问题。。队友写网络流卡了半天。。后来听一个ladao讲懂得。。。用列方程的方法做。
我们假设Xi为i号村庄转出的物资数。假设有四个村庄。A为原本有的物资,B为期望的物资。 //只是看做按一个方向运,其实运进的是负数的话,就可以看出有逆方向运送了。。。
则:
A1-x1+x2=B1 -> x2=x1-(A1-B1)
A2-x2+x3=B2 -> x3=x2-(A2-B2)
A3-x3+x4=B3 -> x4=x3-(A3-B3)
A4-x4+x1=B4 -> x1=x4-(A4-B4) //此处求得C4=0;
我们令A1-B1=C1
则依次往下代入 x3=x1-(A1-B1)-(A2-B2) (A1+A2)-(B1+B2)=C2
x3=X1-C2
x1+x2+x3+x4=(x1-C1)+(x1-C2)+(x1-C3)+x1
我们要求的是令x1+x2+x3+x4尽可能地小,所以就是右边的式子要尽可能地小,我们可以发现其实就是x1到C1,C2,C3的距离的和最小,那么这个x1就是C1…Cn的中位数!中位数到各点的距离之和最小!。。。这方法太吊了。。。然后就可以求出最小的值了。
代码
#include<iostream>
#include<queue>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<string>
#include<cctype>
#include<algorithm>
#include<vector>
#include<set>
#define ll long long
const ll maxn=1e6+5;
using namespace std;
ll a[maxn];
ll b[maxn];
ll c[maxn];
int main()
{
ll n;
while(scanf("%lld",&n)!=EOF)
{ memset(a,0,sizeof(a));
memset(c,0,sizeof(c));
memset(b,0,sizeof(b));
if(n<=0)break;
ll sum1=0,sum2=0;
for(ll i=1;i<=n;i++){scanf("%lld",&a[i]);sum1+=a[i];}
for(ll i=1;i<=n;i++){scanf("%lld",&b[i]);sum2+=b[i];}
if(sum2!=sum1)
{
printf("No way\n");
continue;
}
// c[1]=b[1]-a[1];
for(ll i=1;i<=n;i++)c[i]=c[i-1]+b[i]-a[i];
sort(c,c+n);
ll x=c[n/2],ans=0;
for(ll i=0;i<n;i++)
{
ans+=abs(x-c[i]);
}
printf("%lld\n",ans);
}
return 0;
}