随便写点题,按时间倒序随便刷刷
A.
如果有两个相等可以列等式(i+a_{i mod n}=j+a_{j mod n})
令(i=k_1n+p,j=k_2n+q),则有(k_1n+p+a_p=k_2n+q+a_q)
即存在(p,q),(p+a_p=q+a_q)在(mod n)意义下相等,这个直接判就行了
1 #include<bits/stdc++.h> 2 #define maxn 200005 3 using namespace std; 4 int T,n; 5 int a[maxn]; 6 int main() 7 { 8 scanf("%d",&T); 9 while(T--) 10 { 11 scanf("%d",&n); 12 for(int i=0;i<n;++i)scanf("%d",&a[i]); 13 for(int i=0;i<n;++i)a[i]=((a[i]+i)%n+n)%n; 14 sort(a,a+n); 15 bool fl=0; 16 for(int i=1;i<n;++i)if(a[i]==a[i-1])fl=1; 17 if(fl)puts("NO"); 18 else puts("YES"); 19 } 20 }
B.
考虑同一行/同一列不能出现两个黑块中间有白块的情况:
如果有这样的情况,那么如果这两个黑块都是N磁铁可达的,那么在这行/列的其他位置必然有一个S磁铁,这样随便操作一下N磁铁就进白块了
所以每行/列最多一个连通块
如果是(0)个,那么需要单独考虑(因为每行每列都至少要有一个S,所以必须找出一个位置放S,而这样的位置必须是空行和空列的交点)
其他情况显然合法
最小个数就是每个连通块一个N磁铁
1 #include<bits/stdc++.h> 2 #define maxn 1005 3 using namespace std; 4 int n,m; 5 char a[maxn][maxn]; 6 bool vis[maxn][maxn]; 7 int id[maxn][maxn],cnt; 8 void dfs(int x,int y) 9 { 10 if(a[x][y]!='#')return; 11 if(vis[x][y])return; 12 vis[x][y]=1; 13 id[x][y]=cnt; 14 dfs(x+1,y);dfs(x-1,y);dfs(x,y+1);dfs(x,y-1); 15 } 16 int main() 17 { 18 scanf("%d%d",&n,&m); 19 for(int i=1;i<=n;++i)scanf("%s",a[i]+1); 20 for(int i=1;i<=n;++i) 21 for(int j=1;j<=m;++j)if(a[i][j]=='#'&&(!vis[i][j])) 22 { 23 ++cnt; 24 dfs(i,j); 25 } 26 bool yes=1,y1=0,y2=0; 27 for(int i=1;i<=n;++i) 28 { 29 int lst=0; 30 for(int j=1;j<=m;++j)if(a[i][j]=='#') 31 { 32 if(!lst)lst=j; 33 else 34 { 35 if(j==lst+1)lst=j; 36 else yes=0; 37 } 38 } 39 if(!lst)y1=1; 40 } 41 for(int j=1;j<=m;++j) 42 { 43 int lst=0; 44 for(int i=1;i<=n;++i)if(id[i][j]) 45 { 46 if(!lst)lst=i; 47 else 48 { 49 if(i==lst+1)lst=i; 50 else yes=0; 51 } 52 } 53 if(!lst)y2=1; 54 } 55 if(y1!=y2)yes=0; 56 if(!yes)puts("-1"); 57 else printf("%d ",cnt); 58 }
C.
先判有没有解
显然最松的约束是所有都是存在的情况,这个只要拓扑排序判环就行了
然后考虑找解
还是按照上面的图建图
因为每个变量的出现先后顺序是定的,所以如果某个变量(x_i)被定下来了,那么显然编号大于(i)的并且又和(i)存在大小关系的变量一定是存在
那么我们按编号从小往大考虑,如果一个变量没和之前的变量存在大小关系,那直接贪心的选成任意最优,否则是存在
这个存不存在大小关系就在图上dfs一下前驱后继标记一下就行了
1 #include<bits/stdc++.h> 2 #define maxn 200005 3 using namespace std; 4 int n,m; 5 vector<int> g[maxn],g2[maxn]; 6 int d[maxn]; 7 char Ans[maxn]; 8 bool vis[maxn],vis2[maxn]; 9 void dfs(int u) 10 { 11 if(vis[u])return; 12 vis[u]=1; 13 for(int v:g[u])dfs(v); 14 } 15 void dfs2(int u) 16 { 17 if(vis2[u])return; 18 vis2[u]=1; 19 for(int v:g2[u])dfs2(v); 20 } 21 int main() 22 { 23 scanf("%d%d",&n,&m); 24 for(int i=1;i<=m;++i) 25 { 26 int u,v; 27 scanf("%d%d",&u,&v); 28 g[u].push_back(v); 29 g2[v].push_back(u); 30 d[v]++; 31 } 32 queue<int> q; 33 for(int i=1;i<=n;++i)if(!d[i])q.push(i); 34 int has=0; 35 while(!q.empty()) 36 { 37 int u=q.front();q.pop(); 38 ++has; 39 for(int v:g[u]) 40 { 41 --d[v]; 42 if(!d[v])q.push(v); 43 } 44 } 45 if(has!=n)puts("-1"); 46 else 47 { 48 int ans=0; 49 for(int i=1;i<=n;++i) 50 { 51 if(vis[i]||vis2[i])Ans[i]='E'; 52 else Ans[i]='A',++ans; 53 dfs(i); 54 dfs2(i); 55 } 56 printf("%d ",ans); 57 printf("%s ",Ans+1); 58 } 59 }
D.
一开始想到偏导上去了,但发现并不能处理(b_i leq a_i)的限制条件
考虑计算每次的增量: 在第(i)种从(b_i)到(b_{i+1})时,增量为(a_i-3b_i^2-3b_i-1)
有一个暴力的贪心做法是每次用堆维护最大的增量贪(k)次
但这个(k)很大
发现增量是单调递减的,我们二分最小增量(x),对每种再用一次二分求出(b_i)
这样剩下的零头不会超过(O(n)),按上面用堆贪一下就行了
1 #include<bits/stdc++.h> 2 #define maxn 100005 3 #define ll long long 4 #define mp(a,b) make_pair(a,b) 5 using namespace std; 6 int n; 7 ll k,a[maxn],b[maxn]; 8 ll calc(ll t) 9 { 10 ll tot=0; 11 for(int i=1;i<=n;++i) 12 { 13 ll L=0,R=a[i],ans=0; 14 while(L<=R) 15 { 16 ll M=(L+R)/2; 17 if(a[i]-M*M*3-M*3-1>=t)ans=M,L=M+1; 18 else R=M-1; 19 } 20 b[i]=ans; 21 tot+=ans; 22 } 23 return tot; 24 } 25 int main() 26 { 27 scanf("%d%lld",&n,&k); 28 for(int i=1;i<=n;++i)scanf("%lld",&a[i]); 29 ll L=-(ll)4e18,R=(ll)2e9,ans=R; 30 while(L<=R) 31 { 32 ll M=(L+R)/2; 33 if(calc(M)<=k)ans=M,R=M-1; 34 else L=M+1; 35 } 36 calc(ans); 37 for(int i=1;i<=n;++i)k-=b[i]; 38 priority_queue< pair<ll,int> > pq; 39 for(int i=1;i<=n;++i)if(b[i]<a[i])pq.push(mp(a[i]-b[i]*b[i]*3-b[i]*3-1,i)); 40 for(int i=1;i<=k;++i) 41 { 42 int u=pq.top().second;pq.pop(); 43 ++b[u]; 44 if(b[u]<a[u])pq.push(mp(a[u]-b[u]*b[u]*3-b[u]*3-1,u)); 45 } 46 for(int i=1;i<=n;++i)printf("%lld ",b[i]); 47 }