来源:https://www.jisuanke.com/contest/2625?view=challenges
更新中
A.Tasks
直接贪心
代码:听说当时很多队伍提前拆题甚至上机了,所以很多0min
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<string> #include<stack> #include<queue> #include<deque> #include<set> #include<vector> #include<map> #include<functional> #define fst first #define sc second #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) #define lson l,mid,root<<1 #define rson mid+1,r,root<<1|1 #define lc root<<1 #define rc root<<1|1 #define lowbit(x) ((x)&(-x)) using namespace std; typedef double db; typedef long double ldb; typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> PI; typedef pair<ll,ll> PLL; const db eps = 1e-6; const int mod = 1e9+7; const int maxn = 1e6+100; const int maxm = 6e6+100; //const int inf = 0x3f3f3f3f; const int INF = 0x3f3f3f3f; const int MAXN = maxn; const int MAXM = maxm; const db pi = acos(-1.0); int n, t; int a[maxn]; int main() { scanf("%d %d" ,&n ,&t); for(int i = 0; i < n; i++){ scanf("%d", &a[i]); } sort(a,a+n); int tmp = 0; int ans = 0; for(int i = 0; i < n; i++){ if(tmp+a[i]<=t){ tmp+=a[i];ans++; } }printf("%d", ans); return 0; }
C.Angel's Journey
题意:给定一个圆的圆心(rx, ry),半径r,A的坐标(rx, ry-r),B的坐标(x, y),y>ry,只能走圆上以及圆外y>ry的地方,求A到B的最短路
思路:当x<rx-r或x>rx+r的时候直接从半圆的地方走直线,否则在圆弧上走到切点然后走直线
代码:
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<string> #include<stack> #include<queue> #include<deque> #include<set> #include<vector> #include<map> #include<functional> #define fst first #define sc second #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) #define lson l,mid,root<<1 #define rson mid+1,r,root<<1|1 #define lc root<<1 #define rc root<<1|1 #define lowbit(x) ((x)&(-x)) using namespace std; typedef double db; typedef long double ldb; typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> PI; typedef pair<ll,ll> PLL; const db eps = 1e-6; const int mod = 1e9+7; const int maxn = 1e6+100; const int maxm = 6e6+100; //const int inf = 0x3f3f3f3f; const int INF = 0x3f3f3f3f; const int MAXN = maxn; const int MAXM = maxm; const db pi = acos(-1.0); int n, t; int a[maxn]; int main() { double rx,ry,r,x,y; int t; scanf("%d" ,&t); while(t--){ scanf("%lf %lf %lf %lf %lf", &rx,&ry,&r,&x,&y); double ob = sqrt((x-rx)*(x-rx)+(y-ry)*(y-ry)); double ans = sqrt(ob*ob-r*r)+r*(pi/2.0+asin((y-ry)/ob)-acos(r/ob)); if(x<rx-r||x>rx+r){ if(x<rx-r)rx-=r; if(x>rx+r)rx+=r; ans=pi/2+sqrt((x-rx)*(x-rx)+(y-ry)*(y-ry)); } printf("%.4lf\n",ans); } return 0; }
D.Miku and Generals
题意:n个数,还有m对矛盾的数,n,m<=200,a[i]<=5e4&&(a[i]%100==0),矛盾的不能放在一堆,让你分配这两堆数(都要用完),使得两堆数的和之差最小,输出那个最大的数
思路:将矛盾的值连无向边,因为答案是保证存在的,所以对每一个连通块只有两种选法,通过dfs染色把它们提出来,就是一个背包了,由于a[i]%100==0,所以先除了最后再补俩零也不影响
代码:我tm最后才发现那个a[i]能整除100。。复杂度downdown
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<string> #include<stack> #include<queue> #include<deque> #include<set> #include<vector> #include<map> #include<functional> #define fst first #define sc second #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) #define lson l,mid,root<<1 #define rson mid+1,r,root<<1|1 #define lc root<<1 #define rc root<<1|1 #define lowbit(x) ((x)&(-x)) using namespace std; typedef double db; typedef long double ldb; typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> PI; typedef pair<ll,ll> PLL; const db eps = 1e-6; const int mod = 1e9+7; const int maxn = 1e7+100; const int maxm = 6e6+100; const int inf = 0x3f3f3f3f; const db pi = acos(-1.0); int n, m; vector<int>v[maxn/100]; int vis[maxn/100]; int a[maxn/100]; int f[maxn]; void dfs(int x, int fa, int faa, int co){ if(vis[x]!=-1)return; if(co){ if(x!=fa){a[fa]+=a[x];a[x]=-1;} vis[x]=fa; } else{ if(x!=faa){a[faa]+=a[x];a[x]=-1;} vis[x]=faa; } int t; if(x==fa&&v[x].size()>0)t = v[x][0]; else t=faa; for(int i = 0; i < (int)v[x].size(); i++){ int y = v[x][i]; if(vis[y]==-1){ dfs(y,fa,t,co^1); } } } bool cmp(int a,int b){return a>b;} int main() { int t; scanf("%d" ,&t); int ncase = 0; while(t--){ scanf("%d %d" ,&n, &m); //mem(f,0); ncase++; int sum = 0; for(int i = 1; i <= n; i++){ v[i].clear(); vis[i]=-1; scanf("%d", &a[i]);a[i]/=100;sum+=a[i]; } for(int i = 1; i <= m; i++){ int x,y; scanf("%d %d" ,&x, &y); v[x].pb(y); v[y].pb(x); } for(int i = 1; i <= n; i++){ if(vis[i]==-1){ dfs(i,i,0,1); } } sort(a+1,a+1+n,cmp); int ans=0; f[0]=ncase; for(int i = 1; i <= n; i++){ if(a[i]==-1)break; for(int j = sum; j >= 0; j--){ if(j-a[i]>=0&&f[j-a[i]]==ncase){ //printf(" %d \n",j); f[j]=ncase; if(j<=sum/2)ans=max(ans,j); } } } printf("%d00\n",sum-ans); } return 0; }
J.And And And
题意:一棵有边权的树,对每一对(u,v),如果u到v路径上边权异或和为0,则它对答案的贡献为包含这条路径的树上路径数量,求总答案
思路:以1为根,预处理出各个子树的size,对每一对满足条件的(u,v),因为树上的路径是唯一的,它的贡献应该是u除这条路径外能走的点数*v除这条路径外能走的点数,当u和v在不同链上的时候,答案就是size[u]*size[v];若u和v在同一条链上,其中一个点(例如v)如果是深度较大的点,那么后者就是size[v],前者可以动态统计。
于是可以直接dfs,因为dfs的时候走下来就是一条链,回溯之后就是另一条链,所以在处理同一条链的时候我们可以统计当前点为u时的贡献即可。不同链的时候,我们让它dfs到底,当当前点处理完之后,说明这条链搞完了,就可以一条链一条链更新了,这个看代码好像比较好理解。。。
对了,u到v路径异或和为0可以转化为到根的异或和相等。
代码:long long很烦,而且深搜好像并不需要记录fa。。
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<string> #include<stack> #include<queue> #include<deque> #include<set> #include<vector> #include<map> #include<functional> #include<unordered_map> #define fst first #define sc second #define pb push_back #define mp make_pair #define mem(a,b) memset(a,b,sizeof(a)) #define lson l,mid,root<<1 #define rson mid+1,r,root<<1|1 #define lc root<<1 #define rc root<<1|1 #define lowbit(x) ((x)&(-x)) using namespace std; typedef double db; typedef long double ldb; typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> PI; typedef pair<ll,ll> PLL; const db eps = 1e-6; const int mod = 1e9+7; const int maxn = 1e5+100; const int maxm = 6e6+100; const int inf = 0x3f3f3f3f; const db pi = acos(-1.0); int n; vector<pair<int,ll> >v[maxn]; int sz[maxn]; void dfsInit(int x, int fa){ sz[x]++; for(int i = 0; i < (int)v[x].size(); i++){ int y = v[x][i].fst; if(y!=fa){ dfsInit(y,x); sz[x]+=sz[y]; } } } ll ans; unordered_map<ll,int> num;// the value of gongxian in sta == i ll tmp; void dfs1(int x, int fa, ll sum){//the same line ans += 1ll*num[sum]*sz[x]; ans%=mod; for(int i = 0; i < (int)v[x].size(); i++){ int y = v[x][i].fst; ll w = v[x][i].sc; if(y!=fa){ tmp=(tmp+sz[x]-sz[y]+mod)%mod; num[sum]=(num[sum]+tmp)%mod; dfs1(y,x,sum^w); num[sum]=(num[sum]-tmp+mod)%mod; tmp=(tmp-(sz[x]-sz[y])+mod)%mod; } } } void dfs2(int x, int fa, ll sum){ ans += 1ll*num[sum]*sz[x]; ans%=mod; for(int i = 0; i < (int)v[x].size(); i++){ int y = v[x][i].fst; ll w = v[x][i].sc; if(y==fa)continue; dfs2(y,x,sum^w); } num[sum]+=sz[x]; num[sum]%=mod; } int main() { tmp=ans=0; scanf("%d" ,&n); for(ll i = 2; i <= n; i++){ int x; ll w; scanf("%d %lld", &x, &w); v[x].pb(mp(i,w)); v[i].pb(mp(x,w)); } dfsInit(1,0); dfs1(1,0,0); num.clear(); dfs2(1,0,0); printf("%lld",ans); return 0; }
L.Swap
题意:一个排列可以交换前n/2与后n/2,或前n^1个数奇数位置和偶数位置交换,问通过这两个操作最多产生多少个不同的排列
思路:打表发现从第五项开始是2n, n, 12, 4的规律。或者直接交上打表的模拟,由于只有两条链,而且只有一组数据,也能过
代码:
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<string> #include<stack> #include<queue> #include<deque> #include<set> #include<vector> #include<map> #include<functional> #define fst first #define sc second #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) #define lson l,mid,root<<1 #define rson mid+1,r,root<<1|1 #define lc root<<1 #define rc root<<1|1 #define lowbit(x) ((x)&(-x)) using namespace std; typedef double db; typedef long double ldb; typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> PI; typedef pair<ll,ll> PLL; const db eps = 1e-6; const int mod = 1e9+7; const int maxn = 1e6+100; const int maxm = 6e6+100; const int inf = 0x3f3f3f3f; const db pi = acos(-1.0); int n; int a[maxn],b[maxn]; int ans; void gao1(int a[]){ int l = 1; int r = n/2+1; if(n&1)r++; for(int i = 1; i <= n/2; i++){ swap(a[l+i-1],a[r+i-1]); } return; } void gao2(int a[]){ for(int i = 1; i+1 <= n; i+=2){ //printf(" %d %d %d\n",i,a[i],a[i+1]); swap(a[i],a[i+1]); } return; } int sv(int n){ ::n=n; ans=1; int sta=1; for(int i = 1; i <= n; i++)a[i]=b[i]=i; /*if(n==1)return 1; if(n==2)return 2; if(n==3)return 6;*/ gao1(a);gao2(b); //for(int i = 1; i <= n; i++)printf("%d ",a[i]);printf("\n"); //for(int i = 1; i <= n; i++)printf("%d ",b[i]);printf("\n"); while(1){ //for(int i = 1; i <= n; i++)printf("%d ",a[i]);printf("\n"); //for(int i = 1; i <= n; i++)printf("%d ",b[i]);printf("\n"); int ys = 0; sta^=1; for(int i = 1; i <= n; i++){ if(a[i]!=b[i])ys=1; } if(!ys){ ans++;break; } else{ ans+=2; if(sta) {gao1(a);gao2(b);} else {gao1(b);gao2(a);} } } return ans; } int main() { //scanf("%d" ,&n); //sv(3); for(int i = 1; i <= 100; i++){ printf("%d %d\n",i,sv(i)); } scanf("%d", &n); //for(int i = 1; i <= n; i++)scanf("%d", &a[i]); printf("%d",sv(n)); return 0; }
M.Travel
题意:一个有边权的无向图,刚开始无边可走,每次操作可以增加e条边,增加d点能量,每次操作花费c,问从1走到n最少花费多少,只有这条边加了并且能量不小于边权才能走
思路:我第n次sb。。很明显的二分,而我妄图一次dijk搞完,就把自己搞完了。
很显然操作次数具有单调性,并且因为保证联通,所以答案一定存在。
代码:因为改了很多次,所以很丑
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<string> #include<stack> #include<queue> #include<deque> #include<set> #include<vector> #include<map> #include<functional> #define fst first #define sc second #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) #define lson l,mid,root<<1 #define rson mid+1,r,root<<1|1 #define lc root<<1 #define rc root<<1|1 #define lowbit(x) ((x)&(-x)) using namespace std; typedef double db; typedef long double ldb; typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> PI; typedef pair<ll,ll> PLL; const db eps = 1e-6; const int mod = 1e9+7; const int maxn = 1e6+100; const int maxm = 6e6+100; const int inf = 0x3f3f3f3f; const db pi = acos(-1.0); int vis[maxn]; struct node{ int id,w; node(int a, int b){id=a;w=b;} bool operator < (const node & a) const{ return w>a.w; } }; vector<node>v[maxn]; int n,m; int c, d, e; bool ck(int k){ //printf(" %d\n",k); for(int i = 1; i <= n; i++)vis[i]=0; queue<PI>q; q.push(make_pair(1,0)); while(!q.empty()){ PI top = q.front();q.pop(); int x = top.fst; int d = top.sc; //printf("%d %d ----%d\n",x,d); if(x==n){ if(d<=1ll*e*k)return true; else return false; } if(vis[x])continue; vis[x]=1; for(int i = 0; i < (int)v[x].size(); i++){ node y = v[x][i]; //printf(" %d %d\n",y.id,y.w); if(!vis[y.id]&&1ll*y.w<=1ll*(::d)*k)q.push(make_pair(y.id,d+1)); } } return false; } int main() { scanf("%d %d", &n, &m); scanf("%d %d %d" ,&c, &d, &e); for(int i = 1; i <= m; i++){ int x,y,w; scanf("%d %d %d" ,&x, &y, &w); v[x].pb(node(y,w)); v[y].pb(node(x,w)); } int l, r; l = 0; r = 1e5+100; int ans = -1; while(l<=r){ int mid = (l+r)>>1; if(ck(mid)){ ans = mid; r=mid-1; } else l= mid+1; } printf("%lld",1ll*c*ans); return 0; } /* 3 3 1 99 1 1 2 100 1 3 100 2 3 2 */